Prettier
This commit is contained in:
rodič
b3db1527b8
revize
fe4bfb670b
|
@ -22,6 +22,8 @@
|
||||||
"@sveltejs/kit": "next",
|
"@sveltejs/kit": "next",
|
||||||
"autoprefixer": "^10.4.4",
|
"autoprefixer": "^10.4.4",
|
||||||
"postcss": "^8.4.12",
|
"postcss": "^8.4.12",
|
||||||
|
"prettier": "^2.6.2",
|
||||||
|
"prettier-plugin-svelte": "^2.7.0",
|
||||||
"svelte": "^3.46.0",
|
"svelte": "^3.46.0",
|
||||||
"svelte-markdown": "^0.2.2",
|
"svelte-markdown": "^0.2.2",
|
||||||
"tailwindcss": "^3.0.23"
|
"tailwindcss": "^3.0.23"
|
||||||
|
@ -1571,6 +1573,31 @@
|
||||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin-prettier.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.13.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prettier-plugin-svelte": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-fQhhZICprZot2IqEyoiUYLTRdumULGRvw0o4dzl5jt0jfzVWdGqeYW27QTWAeXhoupEZJULmNoH3ueJwUWFLIA==",
|
||||||
|
"dev": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"prettier": "^1.16.4 || ^2.0.0",
|
||||||
|
"svelte": "^3.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/queue-microtask": {
|
"node_modules/queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
|
@ -2895,6 +2922,19 @@
|
||||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"prettier": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"prettier-plugin-svelte": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-fQhhZICprZot2IqEyoiUYLTRdumULGRvw0o4dzl5jt0jfzVWdGqeYW27QTWAeXhoupEZJULmNoH3ueJwUWFLIA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"queue-microtask": {
|
"queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
"build": "svelte-kit build",
|
"build": "svelte-kit build",
|
||||||
"package": "svelte-kit package",
|
"package": "svelte-kit package",
|
||||||
"preview": "svelte-kit preview",
|
"preview": "svelte-kit preview",
|
||||||
"prepare": "svelte-kit sync"
|
"prepare": "svelte-kit sync",
|
||||||
|
"prettier": "prettier --write --plugin-search-dir=. ./**/*.svelte"
|
||||||
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@faker-js/faker": "^6.1.2",
|
"@faker-js/faker": "^6.1.2",
|
||||||
|
@ -15,6 +17,8 @@
|
||||||
"@sveltejs/kit": "next",
|
"@sveltejs/kit": "next",
|
||||||
"autoprefixer": "^10.4.4",
|
"autoprefixer": "^10.4.4",
|
||||||
"postcss": "^8.4.12",
|
"postcss": "^8.4.12",
|
||||||
|
"prettier": "^2.6.2",
|
||||||
|
"prettier-plugin-svelte": "^2.7.0",
|
||||||
"svelte": "^3.46.0",
|
"svelte": "^3.46.0",
|
||||||
"svelte-markdown": "^0.2.2",
|
"svelte-markdown": "^0.2.2",
|
||||||
"tailwindcss": "^3.0.23"
|
"tailwindcss": "^3.0.23"
|
||||||
|
|
|
@ -1,112 +1,150 @@
|
||||||
<script>
|
<script>
|
||||||
export let speaker;
|
export let speaker;
|
||||||
export let col = 'speakers';
|
export let col = "speakers";
|
||||||
export let size = 'normal';
|
export let size = "normal";
|
||||||
export let customSize = null;
|
export let customSize = null;
|
||||||
|
|
||||||
import SvelteMarkdown from 'svelte-markdown';
|
import SvelteMarkdown from "svelte-markdown";
|
||||||
import Link from '$lib/Link.svelte';
|
import Link from "$lib/Link.svelte";
|
||||||
import { page } from '$app/stores';
|
import { page } from "$app/stores";
|
||||||
|
|
||||||
const renderers = { link: Link }
|
const renderers = { link: Link };
|
||||||
|
|
||||||
let imagesRoot = 'https://spec.utxo.cz/22/photos'
|
let imagesRoot = "https://spec.utxo.cz/22/photos";
|
||||||
/*if ($page.url.hostname === 'localhost') {
|
/*if ($page.url.hostname === 'localhost') {
|
||||||
imagesRoot = 'http://localhost:8000/22/photos'
|
imagesRoot = 'http://localhost:8000/22/photos'
|
||||||
}*/
|
}*/
|
||||||
const priority = [ 'web:svg', 'web:webp', 'web:png', 'web:jpg', 'twitter:jpg' ]
|
const priority = ["web:svg", "web:webp", "web:png", "web:jpg", "twitter:jpg"];
|
||||||
|
|
||||||
$: photos = getPhotos(speaker)
|
$: photos = getPhotos(speaker);
|
||||||
$: speakerImg = photos[0]
|
$: speakerImg = photos[0];
|
||||||
$: speakerImgAlt = photos[1]
|
$: speakerImgAlt = photos[1];
|
||||||
|
|
||||||
function getPhotos(sp) {
|
function getPhotos(sp) {
|
||||||
const output = []
|
const output = [];
|
||||||
if (speaker.photos && speaker.photos.length > 0) {
|
if (speaker.photos && speaker.photos.length > 0) {
|
||||||
for (const prio of priority) {
|
for (const prio of priority) {
|
||||||
if (speaker.photos.includes(prio)) {
|
if (speaker.photos.includes(prio)) {
|
||||||
const [ ext, format ] = prio.split(':')
|
const [ext, format] = prio.split(":");
|
||||||
const fn = `${imagesRoot}/${col}/${speaker.id}-${ext}.${format}`
|
const fn = `${imagesRoot}/${col}/${speaker.id}-${ext}.${format}`;
|
||||||
if (output[0]) {
|
if (output[0]) {
|
||||||
output.push(fn)
|
output.push(fn);
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
output.push(fn)
|
output.push(fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return output
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!speakerImg) {
|
if (!speakerImg) {
|
||||||
speakerImg = '/img/twitter-avatar.png'
|
speakerImg = "/img/twitter-avatar.png";
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFlagEmoji(countryCode) {
|
function getFlagEmoji(countryCode) {
|
||||||
const codePoints = countryCode
|
const codePoints = countryCode
|
||||||
.toUpperCase()
|
.toUpperCase()
|
||||||
.split('')
|
.split("")
|
||||||
.map(char => 127397 + char.charCodeAt());
|
.map((char) => 127397 + char.charCodeAt());
|
||||||
return String.fromCodePoint(...codePoints);
|
return String.fromCodePoint(...codePoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
$: country = speaker.country ? getFlagEmoji(speaker.country) : ''
|
$: country = speaker.country ? getFlagEmoji(speaker.country) : "";
|
||||||
$: currentImg = speakerImg
|
$: currentImg = speakerImg;
|
||||||
|
|
||||||
function mouseOver() {
|
function mouseOver() {
|
||||||
if (speakerImgAlt) {
|
if (speakerImgAlt) {
|
||||||
$: currentImg = speakerImgAlt
|
$: currentImg = speakerImgAlt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function mouseLeave() {
|
function mouseLeave() {
|
||||||
$: currentImg = speakerImg
|
$: currentImg = speakerImg;
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if size === 'custom'}
|
{#if size === "custom"}
|
||||||
<div class="customSize} text-center pb-4 m-auto">
|
<div class="customSize} text-center pb-4 m-auto">
|
||||||
<img src={currentImg} class="{customSize} rounded-full m-auto" alt={speaker.name} />
|
<img
|
||||||
|
src={currentImg}
|
||||||
|
class="{customSize} rounded-full m-auto"
|
||||||
|
alt={speaker.name}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if size === 'big'}
|
{#if size === "big"}
|
||||||
<div class="w-64 text-center pb-4 m-auto">
|
<div class="w-64 text-center pb-4 m-auto">
|
||||||
<img src={currentImg} class="w-64 rounded-full m-auto shadow-xl" alt={speaker.name} on:mouseover={mouseOver} on:mouseleave={mouseLeave} />
|
<img
|
||||||
|
src={currentImg}
|
||||||
|
class="w-64 rounded-full m-auto shadow-xl"
|
||||||
|
alt={speaker.name}
|
||||||
|
on:mouseover={mouseOver}
|
||||||
|
on:mouseleave={mouseLeave}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if size === 'normal'}
|
{#if size === "normal"}
|
||||||
<div class="w-36 sm:w-44 text-center pb-4">
|
<div class="w-36 sm:w-44 text-center pb-4">
|
||||||
<a href="/lide?id={speaker.id}" on:mouseover={mouseOver} on:mouseleave={mouseLeave}><img src={currentImg} class="w-36 sm:w-40 rounded-full m-auto shadow-xl" alt={speaker.name} /></a>
|
<a
|
||||||
<div class="mt-4 text-sm text-blue-web uppercase font-bold"><a href="/lide?id={speaker.id}">{speaker.name}</a> {country}</div>
|
href="/lide?id={speaker.id}"
|
||||||
|
on:mouseover={mouseOver}
|
||||||
|
on:mouseleave={mouseLeave}
|
||||||
|
><img
|
||||||
|
src={currentImg}
|
||||||
|
class="w-36 sm:w-40 rounded-full m-auto shadow-xl"
|
||||||
|
alt={speaker.name}
|
||||||
|
/></a
|
||||||
|
>
|
||||||
|
<div class="mt-4 text-sm text-blue-web uppercase font-bold">
|
||||||
|
<a href="/lide?id={speaker.id}">{speaker.name}</a>
|
||||||
|
{country}
|
||||||
|
</div>
|
||||||
{#if speaker.bio || speaker.orgs}
|
{#if speaker.bio || speaker.orgs}
|
||||||
<div class="mt-1 text-xs text-blue-web italic"><SvelteMarkdown source={speaker.bio || speaker.orgs} renderers={renderers}/></div>
|
<div class="mt-1 text-xs text-blue-web italic">
|
||||||
|
<SvelteMarkdown source={speaker.bio || speaker.orgs} {renderers} />
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if size === 'small'}
|
{#if size === "small"}
|
||||||
<div class="w-16 text-center">
|
<div class="w-16 text-center">
|
||||||
<img src={currentImg} class="w-16 rounded-full m-auto" alt="{speaker.name}" />
|
<img src={currentImg} class="w-16 rounded-full m-auto" alt={speaker.name} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if size === 'semi-small'}
|
{#if size === "semi-small"}
|
||||||
<div class="w-10 text-center">
|
<div class="w-10 text-center">
|
||||||
<img src={currentImg} class="w-10 rounded-full m-auto shadow-md" alt="{speaker.name}" />
|
<img
|
||||||
|
src={currentImg}
|
||||||
|
class="w-10 rounded-full m-auto shadow-md"
|
||||||
|
alt={speaker.name}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if size === 'extra-small'}
|
{#if size === "extra-small"}
|
||||||
<div class="w-6 h-6 text-center">
|
<div class="w-6 h-6 text-center">
|
||||||
<a href="/lide?id={speaker.id}"><img src={currentImg} class="w-6 rounded-full m-auto" alt="{speaker.name}" /></a>
|
<a href="/lide?id={speaker.id}"
|
||||||
|
><img
|
||||||
|
src={currentImg}
|
||||||
|
class="w-6 rounded-full m-auto"
|
||||||
|
alt={speaker.name}
|
||||||
|
/></a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if size === 'micro'}
|
{#if size === "micro"}
|
||||||
<div class="w-4 h-4 text-center">
|
<div class="w-4 h-4 text-center">
|
||||||
<a href="/lide?id={speaker.id}"><img src={currentImg} class="w-4 rounded-full m-auto" alt="{speaker.name}" /></a>
|
<a href="/lide?id={speaker.id}"
|
||||||
|
><img
|
||||||
|
src={currentImg}
|
||||||
|
class="w-4 rounded-full m-auto"
|
||||||
|
alt={speaker.name}
|
||||||
|
/></a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -3,53 +3,70 @@
|
||||||
|
|
||||||
const e = event;
|
const e = event;
|
||||||
|
|
||||||
import Avatar from '$lib/Avatar.svelte';
|
import Avatar from "$lib/Avatar.svelte";
|
||||||
import EventTypeLabel from '$lib/EventTypeLabel.svelte';
|
import EventTypeLabel from "$lib/EventTypeLabel.svelte";
|
||||||
|
|
||||||
import { bundle, userData } from '$lib/stores.js';
|
import { bundle, userData } from "$lib/stores.js";
|
||||||
|
|
||||||
function speakersMap(arr) {
|
function speakersMap(arr) {
|
||||||
if (!arr) return;
|
if (!arr) return;
|
||||||
return arr.map(sId => {
|
return arr.map((sId) => {
|
||||||
return $bundle.spec.speakers.find(sp => sp.id === sId)
|
return $bundle.spec.speakers.find((sp) => sp.id === sId);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function trackRender(trackId) {
|
function trackRender(trackId) {
|
||||||
const track = $bundle.spec.tracks.find(t => t.id === trackId)
|
const track = $bundle.spec.tracks.find((t) => t.id === trackId);
|
||||||
return track.shortname || track.name
|
return track.shortname || track.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getParents(e) {
|
function getParents(e) {
|
||||||
return $bundle.spec.events.filter(i => i.parent === e.id)
|
return $bundle.spec.events.filter((i) => i.parent === e.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFavorite(el) {
|
function handleFavorite(el) {
|
||||||
const t = el.target.getAttribute('utxo-event-id')
|
const t = el.target.getAttribute("utxo-event-id");
|
||||||
userData.update(data => {
|
userData.update((data) => {
|
||||||
const fe = data.favoriteEvents
|
const fe = data.favoriteEvents;
|
||||||
let output = null
|
let output = null;
|
||||||
if (fe.includes(t)) {
|
if (fe.includes(t)) {
|
||||||
output = Object.assign($userData, { favoriteEvents: fe.filter(f => f !== t) } )
|
output = Object.assign($userData, {
|
||||||
|
favoriteEvents: fe.filter((f) => f !== t),
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
fe.push(t)
|
fe.push(t);
|
||||||
output = Object.assign($userData, { favoriteEvents: fe })
|
output = Object.assign($userData, { favoriteEvents: fe });
|
||||||
}
|
}
|
||||||
//localStorage.setItem('userData', JSON.stringify(output))
|
//localStorage.setItem('userData', JSON.stringify(output))
|
||||||
return output
|
return output;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
<div class="transition-all mb-4 border px-3 py-2 rounded-md shadow {$userData.favoriteEvents.includes(e.id) ? 'bg-yellow-100' : '' }" >
|
class="transition-all mb-4 border px-3 py-2 rounded-md shadow {$userData.favoriteEvents.includes(
|
||||||
<div class="float-right"><i class="fa-star {$userData.favoriteEvents.includes(e.id) ? 'fa-solid' : 'fa-regular'} cursor-pointer" utxo-event-id="{e.id}" on:click={handleFavorite}></i></div>
|
e.id
|
||||||
<div class="text-lg font-semibold"><a href="/udalosti?id={e.id}">{e.name}</a></div>
|
)
|
||||||
|
? 'bg-yellow-100'
|
||||||
|
: ''}"
|
||||||
|
>
|
||||||
|
<div class="float-right">
|
||||||
|
<i
|
||||||
|
class="fa-star {$userData.favoriteEvents.includes(e.id)
|
||||||
|
? 'fa-solid'
|
||||||
|
: 'fa-regular'} cursor-pointer"
|
||||||
|
utxo-event-id={e.id}
|
||||||
|
on:click={handleFavorite}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="text-lg font-semibold">
|
||||||
|
<a href="/udalosti?id={e.id}">{e.name}</a>
|
||||||
|
</div>
|
||||||
{#if e.speakers && e.speakers.length > 0}
|
{#if e.speakers && e.speakers.length > 0}
|
||||||
<div class="mt-1 mb-2 flex flex-wrap gap-2">
|
<div class="mt-1 mb-2 flex flex-wrap gap-2">
|
||||||
{#each speakersMap(e.speakers) as s}
|
{#each speakersMap(e.speakers) as s}
|
||||||
<div class="flex gap-1.5">
|
<div class="flex gap-1.5">
|
||||||
<Avatar speaker={s} size='extra-small' />
|
<Avatar speaker={s} size="extra-small" />
|
||||||
<div class="m-auto"><a href="/lide?id={s.id}">{s.name}</a></div>
|
<div class="m-auto"><a href="/lide?id={s.id}">{s.name}</a></div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -65,13 +82,18 @@
|
||||||
<div class="flex flex-wrap gap-2" cellpadding="5">
|
<div class="flex flex-wrap gap-2" cellpadding="5">
|
||||||
{#each getParents(e) as pe}
|
{#each getParents(e) as pe}
|
||||||
<div class="border rounded py-1.5 px-2.5 bg-gray-100 text-sm">
|
<div class="border rounded py-1.5 px-2.5 bg-gray-100 text-sm">
|
||||||
<div class="font-bold"><a href="/udalosti?id={pe.id}">{pe.name}</a></div>
|
<div class="font-bold">
|
||||||
|
<a href="/udalosti?id={pe.id}">{pe.name}</a>
|
||||||
|
</div>
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
{#if pe.speakers.length === 0}
|
{#if pe.speakers.length === 0}
|
||||||
<div>TBA</div>
|
<div>TBA</div>
|
||||||
{:else}
|
{:else}
|
||||||
{#each speakersMap(pe.speakers) as s}
|
{#each speakersMap(pe.speakers) as s}
|
||||||
<div class="flex gap-1"><Avatar speaker={s} size='micro' /><div><a href="/lide?id={s.id}">{s.name}</a></div></div>
|
<div class="flex gap-1">
|
||||||
|
<Avatar speaker={s} size="micro" />
|
||||||
|
<div><a href="/lide?id={s.id}">{s.name}</a></div>
|
||||||
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,19 +3,23 @@
|
||||||
export let size = null;
|
export let size = null;
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
panel: { title: 'Panelová debata', style: 'bg-custom-red text-white' },
|
panel: { title: "Panelová debata", style: "bg-custom-red text-white" },
|
||||||
talk: { title: 'Přednáška', style: 'bg-custom-green text-white' },
|
talk: { title: "Přednáška", style: "bg-custom-green text-white" },
|
||||||
workshop: { title: 'Workshop', style: 'bg-custom-blue text-white' },
|
workshop: { title: "Workshop", style: "bg-custom-blue text-white" },
|
||||||
other: { title: 'Ostatní', style: 'bg-custom-yellow' },
|
other: { title: "Ostatní", style: "bg-custom-yellow" },
|
||||||
lightning: { title: 'Lightning talk', style: 'bg-pink-400' },
|
lightning: { title: "Lightning talk", style: "bg-pink-400" },
|
||||||
}
|
};
|
||||||
|
|
||||||
const current = config[event.type];
|
const 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="w-1 rounded-l-sm {current.style}" />
|
||||||
<div class="{ size === 'big' ? 'px-2 py-0.5' : 'px-1.5 py-0.5' } rounded-r-sm bg-gray-100 uppercase">{current.title}</div>
|
<div
|
||||||
|
class="{size === 'big'
|
||||||
|
? 'px-2 py-0.5'
|
||||||
|
: 'px-1.5 py-0.5'} rounded-r-sm bg-gray-100 uppercase"
|
||||||
|
>
|
||||||
|
{current.title}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
<script>
|
<script>
|
||||||
import { bundle } from '$lib/stores';
|
import { bundle } from "$lib/stores";
|
||||||
import SocialButtons from '$lib/SocialButtons.svelte';
|
import SocialButtons from "$lib/SocialButtons.svelte";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $bundle}
|
{#if $bundle}
|
||||||
<div class="bg-blue-web-bg text-white">
|
<div class="bg-blue-web-bg text-white">
|
||||||
<div class="relative mx-auto px-6 pt-10 pb-2 sm:pb-6 max-w-6xl sm:flex pr-4">
|
<div
|
||||||
|
class="relative mx-auto px-6 pt-10 pb-2 sm:pb-6 max-w-6xl sm:flex pr-4"
|
||||||
|
>
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div>
|
<div>
|
||||||
<a href="/"><img src="/img/logo-white.svg" alt="UTXO.22" class="w-24" /></a>
|
<a href="/"
|
||||||
|
><img src="/img/logo-white.svg" alt="UTXO.22" class="w-24" /></a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4 font-semibold">
|
<div class="mt-4 font-semibold">
|
||||||
4.-5. červen 2022 @ Gabriel Loci, Praha
|
4.-5. červen 2022 @ Gabriel Loci, Praha
|
||||||
|
@ -17,21 +21,42 @@
|
||||||
Otevřená komunitní kryptoměnová konference
|
Otevřená komunitní kryptoměnová konference
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<a href="{$bundle.links.docs}" class="hover:text-red-500"><i class="fas fa-book" /> Dokumentace</a>
|
<a href={$bundle.links.docs} class="hover:text-red-500"
|
||||||
|
><i class="fas fa-book" /> Dokumentace</a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sm:mt-0 mt-6 sm:w-1/3 mr-2">
|
<div class="sm:mt-0 mt-6 sm:w-1/3 mr-2">
|
||||||
<SocialButtons size="normal" />
|
<SocialButtons size="normal" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative mx-auto px-6 pt-10 pb-6 max-w-6xl text-xs opacity-50 sm:flex">
|
<div
|
||||||
|
class="relative mx-auto px-6 pt-10 pb-6 max-w-6xl text-xs opacity-50 sm:flex"
|
||||||
|
>
|
||||||
<div class="flex-1 mt-2 mb-2">
|
<div class="flex-1 mt-2 mb-2">
|
||||||
<i class="fas fa-heart text-red-500" /> S láskou organizuje <a href="https://utxo.foundation" class="underline hover:no-underline" target="_blank">UTXO Foundation, z.s.</a>
|
<i class="fas fa-heart text-red-500" /> S láskou organizuje
|
||||||
|
<a
|
||||||
|
href="https://utxo.foundation"
|
||||||
|
class="underline hover:no-underline"
|
||||||
|
target="_blank">UTXO Foundation, z.s.</a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://github.com/utxo-foundation/utxo22-web" target="_blank"><span class="font-bold">v0.9.1</span></a> | powered by
|
<a href="https://github.com/utxo-foundation/utxo22-web" target="_blank"
|
||||||
<a href="https://svelte.dev/" class="font-bold" target="_blank" ><img src="/img/svelte-logo.svg" class="w-5 inline" alt="Svelte" /> Svelte</a> |
|
><span class="font-bold">v0.9.1</span></a
|
||||||
grafický návrh <a href="https://www.ppmedia.cz/" target="_blank"><img src="/img/pen-production-logo.svg" class="w-28 inline-block pb-2 ml-1" alt="Pen&Production" /></a>
|
>
|
||||||
|
| powered by
|
||||||
|
<a href="https://svelte.dev/" class="font-bold" target="_blank"
|
||||||
|
><img src="/img/svelte-logo.svg" class="w-5 inline" alt="Svelte" /> Svelte</a
|
||||||
|
>
|
||||||
|
| grafický návrh
|
||||||
|
<a href="https://www.ppmedia.cz/" target="_blank"
|
||||||
|
><img
|
||||||
|
src="/img/pen-production-logo.svg"
|
||||||
|
class="w-28 inline-block pb-2 ml-1"
|
||||||
|
alt="Pen&Production"
|
||||||
|
/></a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
export let href = ''
|
export let href = "";
|
||||||
export let title = undefined
|
export let title = undefined;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<a {href} {title} class="underline hover:no-underline" target="_blank"><slot></slot></a>
|
<a {href} {title} class="underline hover:no-underline" target="_blank"
|
||||||
|
><slot /></a
|
||||||
|
>
|
||||||
|
|
|
@ -1,34 +1,42 @@
|
||||||
<script>
|
<script>
|
||||||
export let size = 'small';
|
export let size = "small";
|
||||||
|
|
||||||
import { bundle } from '$lib/stores';
|
import { bundle } from "$lib/stores";
|
||||||
import { page } from '$app/stores';
|
import { page } from "$app/stores";
|
||||||
|
|
||||||
const socials = [
|
const socials = [
|
||||||
{ link: 'twitter', ico: 'fa-brands fa-twitter', name: 'Twitter' },
|
{ link: "twitter", ico: "fa-brands fa-twitter", name: "Twitter" },
|
||||||
{ link: 'instagram', ico: 'fab fa-instagram', name: 'Instagram' },
|
{ link: "instagram", ico: "fab fa-instagram", name: "Instagram" },
|
||||||
{ link: 'fbevent', ico: 'fab fa-facebook', name: 'Facebook' },
|
{ link: "fbevent", ico: "fab fa-facebook", name: "Facebook" },
|
||||||
{ link: 'substack', ico: 'fa-solid fa-envelope', name: 'Newsletter' },
|
{ link: "substack", ico: "fa-solid fa-envelope", name: "Newsletter" },
|
||||||
{ link: 'discord', ico: 'fab fa-discord', name: 'Discord' },
|
{ link: "discord", ico: "fab fa-discord", name: "Discord" },
|
||||||
{ link: 'telegram', ico: 'fab fa-telegram', name: 'Telegram' },
|
{ link: "telegram", ico: "fab fa-telegram", name: "Telegram" },
|
||||||
]
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $bundle}
|
{#if $bundle}
|
||||||
{#if size === 'small'}
|
{#if size === "small"}
|
||||||
<div class="flex block space-x-2 m-auto w-full justify-end">
|
<div class="flex block space-x-2 m-auto w-full justify-end">
|
||||||
{#each socials as soc}
|
{#each socials as soc}
|
||||||
<a href="{$bundle.links[soc.link]}" class="w-6 h-6 bg-white rounded-full hover:bg-utxo-gradient hover:text-white" target="_blank">
|
<a
|
||||||
<i class="{soc.ico}" />
|
href={$bundle.links[soc.link]}
|
||||||
|
class="w-6 h-6 bg-white rounded-full hover:bg-utxo-gradient hover:text-white"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<i class={soc.ico} />
|
||||||
</a>
|
</a>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if size === 'normal'}
|
{#if size === "normal"}
|
||||||
<div class="w-auto">
|
<div class="w-auto">
|
||||||
<div class="sm:flex flex-wrap gap-3 justify-end">
|
<div class="sm:flex flex-wrap gap-3 justify-end">
|
||||||
{#each socials as soc}
|
{#each socials as soc}
|
||||||
<div class="mr-4 sm:mr-0 inline-block sm:block hover:text-red-500"><a href="{$bundle.links[soc.link]}" class="block flex" target="_blank"><i class="{soc.ico} mr-2 my-auto" />{soc.name}</a></div>
|
<div class="mr-4 sm:mr-0 inline-block sm:block hover:text-red-500">
|
||||||
|
<a href={$bundle.links[soc.link]} class="block flex" target="_blank"
|
||||||
|
><i class="{soc.ico} mr-2 my-auto" />{soc.name}</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,31 +1,61 @@
|
||||||
<script>
|
<script>
|
||||||
import { page } from '$app/stores';
|
import { page } from "$app/stores";
|
||||||
import { bundle, userData, userDataLocal } from '$lib/stores';
|
import { bundle, userData, userDataLocal } from "$lib/stores";
|
||||||
import SocialButtons from '$lib/SocialButtons.svelte';
|
import SocialButtons from "$lib/SocialButtons.svelte";
|
||||||
|
|
||||||
function logoClick() {
|
function logoClick() {
|
||||||
userData.update(ud => {
|
userData.update((ud) => {
|
||||||
ud.hpTrack = 'top'
|
ud.hpTrack = "top";
|
||||||
return ud
|
return ud;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="relative" style="background-color: #32375C;">
|
<header class="relative" style="background-color: #32375C;">
|
||||||
<!-- <li class:active={$page.url.pathname === '/'}><a sveltekit:prefetch href="/">Home</a></li> -->
|
<!-- <li class:active={$page.url.pathname === '/'}><a sveltekit:prefetch href="/">Home</a></li> -->
|
||||||
<nav class="relative mx-auto lg:px-6 px-4 pt-4 sm:pt-6 sm:pb-6 pb-2 max-w-6xl text-center">
|
<nav
|
||||||
|
class="relative mx-auto lg:px-6 px-4 pt-4 sm:pt-6 sm:pb-6 pb-2 max-w-6xl text-center"
|
||||||
|
>
|
||||||
<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">
|
||||||
<div class="block justify-start lg:flex-1 my-auto text-center pb-3 lg:pb-0">
|
<div
|
||||||
<div class="w-36 lg:w-24 inline-block lg:block"><a href="/" on:click={logoClick}><img src="/img/logo-white.svg" class="w-full" alt="UTXO.22" /></a></div>
|
class="block justify-start lg:flex-1 my-auto text-center pb-3 lg:pb-0"
|
||||||
|
>
|
||||||
|
<div class="w-36 lg:w-24 inline-block lg:block">
|
||||||
|
<a href="/" on:click={logoClick}
|
||||||
|
><img src="/img/logo-white.svg" class="w-full" alt="UTXO.22" /></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex lg:space-x-10 uppercase text-sm font-bold text-white">
|
<div class="flex lg:space-x-10 uppercase text-sm font-bold text-white">
|
||||||
<a sveltekit:prefetch href="/" class="lg:w-auto w-1/3 m-auto hover:text-[#E16A61]" class:text-blue-400={$page.url.pathname === '/'}>O konferenci</a>
|
<a
|
||||||
<a sveltekit:prefetch href="/program" class="lg:w-auto w-1/3 m-auto hover:text-[#E16A61]" class:text-blue-400={$page.url.pathname === '/program'}>Program</a>
|
sveltekit:prefetch
|
||||||
<a sveltekit:prefetch href="/vstupenky" class="lg:w-auto w-1/3 m-auto border-solid border border-[#E16A61] rounded-full {$page.url.pathname === '/vstupenky' ? 'border-0 bg-utxo-gradient m-px' : 'hover:border-0 hover:bg-utxo-gradient hover:p-px' }"><div class="py-2 px-1 lg:px-8">Vstupenky{#if $userDataLocal.tickets && $userDataLocal.tickets.length > 0} ({$userDataLocal.tickets.length}){/if}</div></a>
|
href="/"
|
||||||
|
class="lg:w-auto w-1/3 m-auto hover:text-[#E16A61]"
|
||||||
|
class:text-blue-400={$page.url.pathname === "/"}>O konferenci</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
sveltekit:prefetch
|
||||||
|
href="/program"
|
||||||
|
class="lg:w-auto w-1/3 m-auto hover:text-[#E16A61]"
|
||||||
|
class:text-blue-400={$page.url.pathname === "/program"}>Program</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
sveltekit:prefetch
|
||||||
|
href="/vstupenky"
|
||||||
|
class="lg:w-auto w-1/3 m-auto border-solid border border-[#E16A61] rounded-full {$page
|
||||||
|
.url.pathname === '/vstupenky'
|
||||||
|
? 'border-0 bg-utxo-gradient m-px'
|
||||||
|
: 'hover:border-0 hover:bg-utxo-gradient hover:p-px'}"
|
||||||
|
><div class="py-2 px-1 lg:px-8">
|
||||||
|
Vstupenky{#if $userDataLocal.tickets && $userDataLocal.tickets.length > 0} ({$userDataLocal
|
||||||
|
.tickets.length}){/if}
|
||||||
|
</div></a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="hidden lg:block my-auto lg:flex-1 lg:pt-0 pt-4 lg:justify-end justify-center">
|
<div
|
||||||
|
class="hidden lg:block my-auto lg:flex-1 lg:pt-0 pt-4 lg:justify-end justify-center"
|
||||||
|
>
|
||||||
<SocialButtons />
|
<SocialButtons />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,40 +1,37 @@
|
||||||
<script>
|
<script>
|
||||||
import Header from '$lib/header/Header.svelte';
|
import Header from "$lib/header/Header.svelte";
|
||||||
import Footer from '$lib/Footer.svelte';
|
import Footer from "$lib/Footer.svelte";
|
||||||
import '../app.css';
|
import "../app.css";
|
||||||
import api from '$lib/api.js';
|
import api from "$lib/api.js";
|
||||||
import { page } from '$app/stores';
|
import { page } from "$app/stores";
|
||||||
import { userData, userDataLocal, apiStatus } from '$lib/stores';
|
import { userData, userDataLocal, apiStatus } from "$lib/stores";
|
||||||
import { loadOrders, loadApiStatus } from '$lib/orders';
|
import { loadOrders, loadApiStatus } from "$lib/orders";
|
||||||
import { onMount, onDestroy } from 'svelte';
|
import { onMount, onDestroy } from "svelte";
|
||||||
|
|
||||||
let bundle = null
|
let bundle = null;
|
||||||
let uds = null
|
let uds = null;
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
bundle = await api.loadBundle($page.url.hostname === 'localhost')
|
bundle = await api.loadBundle($page.url.hostname === "localhost");
|
||||||
|
|
||||||
const userDataLS = localStorage.getItem('userData')
|
const userDataLS = localStorage.getItem("userData");
|
||||||
if (userDataLS) {
|
if (userDataLS) {
|
||||||
userData.set(JSON.parse(userDataLS))
|
userData.set(JSON.parse(userDataLS));
|
||||||
}
|
}
|
||||||
|
|
||||||
uds = userData.subscribe(ud => {
|
uds = userData.subscribe((ud) => {
|
||||||
localStorage.setItem('userData', JSON.stringify(ud))
|
localStorage.setItem("userData", JSON.stringify(ud));
|
||||||
})
|
});
|
||||||
|
|
||||||
await loadApiStatus()
|
await loadApiStatus();
|
||||||
await loadOrders($userData)
|
await loadOrders($userData);
|
||||||
})
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
//userData.unsubscribe(uds)
|
//userData.unsubscribe(uds)
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// load orders
|
// load orders
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if bundle}
|
{#if bundle}
|
||||||
|
|
|
@ -7,11 +7,41 @@
|
||||||
|
|
||||||
<section class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl text-blue-web">
|
<section class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl text-blue-web">
|
||||||
<div class="">
|
<div class="">
|
||||||
<div class="text-3xl lg:text-4xl text-center">🎉 Gratulujeme k nákupu vstupenek!</div>
|
<div class="text-3xl lg:text-4xl text-center">
|
||||||
<div class="mt-4 text-lg text-center">Najdeš je v mailu nebo na stránce <a href="/vstupenky" class="underline hover:no-underline">vstupenky</a></div>
|
🎉 Gratulujeme k nákupu vstupenek!
|
||||||
<div class="flex mt-6"><img class="m-auto w-auto lg:max-w-3xl" src="/gifs/funny-celebrate-{Math.round((Math.random() * (9 - 1) + 1))}.gif" /></div>
|
</div>
|
||||||
<div class="mt-10 text-xl text-center mt-6">Co teď? Poděl se o tu radost s ostatními <a href="https://twitter.com/intent/tweet?text=M%C3%A1m%20l%C3%ADstek%20na%20%40utxoprague%20%F0%9F%8E%89%20Poj%C4%8F%20taky%21%0A%20%23utxo22" class="underline hover:no-underline" target="_blank">tweetem</a></div>
|
<div class="mt-4 text-lg text-center">
|
||||||
<div class="text-xl text-center mt-6">Prohlédni si <a href="/program" class="underline hover:no-underline">aktuální program</a></div>
|
Najdeš je v mailu nebo na stránce <a
|
||||||
<div class="text-xl text-center mt-6">Sleduj novinky na <a href="https://twitter.com/utxoprague" class="underline hover:no-underline" target="_blank">Twitteru</a> <i class="fa-brands fa-twitter"></i></div>
|
href="/vstupenky"
|
||||||
|
class="underline hover:no-underline">vstupenky</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="flex mt-6">
|
||||||
|
<img
|
||||||
|
class="m-auto w-auto lg:max-w-3xl"
|
||||||
|
src="/gifs/funny-celebrate-{Math.round(
|
||||||
|
Math.random() * (9 - 1) + 1
|
||||||
|
)}.gif"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mt-10 text-xl text-center mt-6">
|
||||||
|
Co teď? Poděl se o tu radost s ostatními <a
|
||||||
|
href="https://twitter.com/intent/tweet?text=M%C3%A1m%20l%C3%ADstek%20na%20%40utxoprague%20%F0%9F%8E%89%20Poj%C4%8F%20taky%21%0A%20%23utxo22"
|
||||||
|
class="underline hover:no-underline"
|
||||||
|
target="_blank">tweetem</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="text-xl text-center mt-6">
|
||||||
|
Prohlédni si <a href="/program" class="underline hover:no-underline"
|
||||||
|
>aktuální program</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="text-xl text-center mt-6">
|
||||||
|
Sleduj novinky na <a
|
||||||
|
href="https://twitter.com/utxoprague"
|
||||||
|
class="underline hover:no-underline"
|
||||||
|
target="_blank">Twitteru</a
|
||||||
|
> <i class="fa-brands fa-twitter" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -3,59 +3,92 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { bundle, userData } from '$lib/stores.js';
|
import { bundle, userData } from "$lib/stores.js";
|
||||||
import Avatar from '$lib/Avatar.svelte';
|
import Avatar from "$lib/Avatar.svelte";
|
||||||
import SvelteMarkdown from 'svelte-markdown';
|
import SvelteMarkdown from "svelte-markdown";
|
||||||
import Link from '$lib/Link.svelte';
|
import Link from "$lib/Link.svelte";
|
||||||
const renderers = { link: Link }
|
const renderers = { link: Link };
|
||||||
|
|
||||||
let onlyLead = true
|
let onlyLead = true;
|
||||||
let onlyLeadPreview = false
|
let onlyLeadPreview = false;
|
||||||
|
|
||||||
$: currentBundle = $bundle;
|
$: currentBundle = $bundle;
|
||||||
$: leadSpeakersCount = currentBundle ? currentBundle.spec.speakers.filter(s => !!s.lead).length : 0
|
$: leadSpeakersCount = currentBundle
|
||||||
$: tracks = currentBundle ? [{ name: 'Hlavní přednášející ('+leadSpeakersCount+')', id: 'top' }, { name: 'Vše', id: null }].concat(currentBundle.spec.tracks) : null
|
? currentBundle.spec.speakers.filter((s) => !!s.lead).length
|
||||||
|
: 0;
|
||||||
|
$: tracks = currentBundle
|
||||||
|
? [
|
||||||
|
{ name: "Hlavní přednášející (" + leadSpeakersCount + ")", id: "top" },
|
||||||
|
{ name: "Vše", id: null },
|
||||||
|
].concat(currentBundle.spec.tracks)
|
||||||
|
: null;
|
||||||
|
|
||||||
function changeTrack(tId) {
|
function changeTrack(tId) {
|
||||||
return function () {
|
return function () {
|
||||||
userData.update(ud => { ud.hpTrack = tId; return ud; })
|
userData.update((ud) => {
|
||||||
onlyLead = !tId
|
ud.hpTrack = tId;
|
||||||
}
|
return ud;
|
||||||
|
});
|
||||||
|
onlyLead = !tId;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleShowFull() {
|
function handleShowFull() {
|
||||||
userData.update(ud => { ud.hpTrack = null; return ud })
|
userData.update((ud) => {
|
||||||
|
ud.hpTrack = null;
|
||||||
|
return ud;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>UTXO.22 - 4-5. červen 2022 {$bundle ? '- '+$bundle.description : ''}</title>
|
<title
|
||||||
|
>UTXO.22 - 4-5. červen 2022 {$bundle
|
||||||
|
? "- " + $bundle.description
|
||||||
|
: ""}</title
|
||||||
|
>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<section class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl">
|
<section class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl">
|
||||||
{#if $bundle}
|
{#if $bundle}
|
||||||
<div class="flex flex-wrap gap-1.5 sm:gap-3 text-xs uppercase font-bold text-blue-web justify-left">
|
<div
|
||||||
|
class="flex flex-wrap gap-1.5 sm:gap-3 text-xs uppercase font-bold text-blue-web justify-left"
|
||||||
|
>
|
||||||
{#each tracks as track}
|
{#each tracks as track}
|
||||||
<div class="py-1.5 sm:py-2 px-2.5 sm:px-8 rounded-full shadow border border-solid {$userData.hpTrack === track.id ? 'bg-utxo-gradient border-0 text-white' : 'border-blue-web hover:bg-blue-web hover:text-white hover:border-transparent cursor-pointer'}" on:click={changeTrack(track.id)}>{track.shortname || track.name} {#if !track.id}({$bundle.spec.speakers.length}){/if}</div>
|
<div
|
||||||
|
class="py-1.5 sm:py-2 px-2.5 sm:px-8 rounded-full shadow border border-solid {$userData.hpTrack ===
|
||||||
|
track.id
|
||||||
|
? 'bg-utxo-gradient border-0 text-white'
|
||||||
|
: 'border-blue-web hover:bg-blue-web hover:text-white hover:border-transparent cursor-pointer'}"
|
||||||
|
on:click={changeTrack(track.id)}
|
||||||
|
>
|
||||||
|
{track.shortname || track.name}
|
||||||
|
{#if !track.id}({$bundle.spec.speakers.length}){/if}
|
||||||
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-wrap gap-6 mt-6 sm:mt-14 justify-center">
|
<div class="flex flex-wrap gap-6 mt-6 sm:mt-14 justify-center">
|
||||||
{#each $bundle.spec.speakers as speaker}
|
{#each $bundle.spec.speakers as speaker}
|
||||||
{#if ($userData.hpTrack === 'top' && speaker.lead === true) || $userData.hpTrack !== 'top'}
|
{#if ($userData.hpTrack === "top" && speaker.lead === true) || $userData.hpTrack !== "top"}
|
||||||
{#if (!$userData.hpTrack || speaker.tracks.includes($userData.hpTrack)) || $userData.hpTrack === 'top'}
|
{#if !$userData.hpTrack || speaker.tracks.includes($userData.hpTrack) || $userData.hpTrack === "top"}
|
||||||
<Avatar speaker={speaker} />
|
<Avatar {speaker} />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{#if $userData.hpTrack === 'top'}
|
{#if $userData.hpTrack === "top"}
|
||||||
<div class="relative cursor-pointer mb-10">
|
<div class="relative cursor-pointer mb-10">
|
||||||
<div class="absolute inset-0 bg-gradient-to-b from-transparent to-white flex" on:click={handleShowFull}></div>
|
<div
|
||||||
|
class="absolute inset-0 bg-gradient-to-b from-transparent to-white flex"
|
||||||
|
on:click={handleShowFull}
|
||||||
|
/>
|
||||||
<div class="flex flex-wrap gap-3 mt-10 justify-center">
|
<div class="flex flex-wrap gap-3 mt-10 justify-center">
|
||||||
{#each $bundle.spec.speakers.filter(s => !s.lead).sort(() => .5 - Math.random()).slice(0,27) as speaker}
|
{#each $bundle.spec.speakers
|
||||||
<Avatar speaker={speaker} size="small" />
|
.filter((s) => !s.lead)
|
||||||
|
.sort(() => 0.5 - Math.random())
|
||||||
|
.slice(0, 27) as speaker}
|
||||||
|
<Avatar {speaker} size="small" />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -67,24 +100,57 @@
|
||||||
<div class="relative mx-auto py-6 px-6 max-w-6xl">
|
<div class="relative mx-auto py-6 px-6 max-w-6xl">
|
||||||
<div class="py-6 md:py-10 md:flex gap-12">
|
<div class="py-6 md:py-10 md:flex gap-12">
|
||||||
<div class="block flex-1">
|
<div class="block flex-1">
|
||||||
<img src="/photos/gabriel-loci.jpeg" class="flex rounded-xl shadow-xl" alt="Gabriel Loci" />
|
<img
|
||||||
|
src="/photos/gabriel-loci.jpeg"
|
||||||
|
class="flex rounded-xl shadow-xl"
|
||||||
|
alt="Gabriel Loci"
|
||||||
|
/>
|
||||||
<div class="flex mt-3 gap-3">
|
<div class="flex mt-3 gap-3">
|
||||||
<div class="w-1/2"><img src="/photos/rajska-zahrada.jpeg" class="rounded-lg shadow-lg" alt="Gabriel Loci - Rajská zahrada" /></div>
|
<div class="w-1/2">
|
||||||
<div class="w-1/2"><img src="/photos/knihovna.jpeg" class="rounded-lg shadow-lg" alt="Gabriel Loci - Knihovna" /></div>
|
<img
|
||||||
|
src="/photos/rajska-zahrada.jpeg"
|
||||||
|
class="rounded-lg shadow-lg"
|
||||||
|
alt="Gabriel Loci - Rajská zahrada"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="w-1/2">
|
||||||
|
<img
|
||||||
|
src="/photos/knihovna.jpeg"
|
||||||
|
class="rounded-lg shadow-lg"
|
||||||
|
alt="Gabriel Loci - Knihovna"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-white md:w-1/2 md:pt-0 pt-6">
|
<div class="text-white md:w-1/2 md:pt-0 pt-6">
|
||||||
<div class="uppercase">Místo</div>
|
<div class="uppercase">Místo</div>
|
||||||
<div class="uppercase mt-3 text-4xl font-bold">Gabriel Loci</div>
|
<div class="uppercase mt-3 text-4xl font-bold">Gabriel Loci</div>
|
||||||
<div class="mt-4 font-bold">
|
<div class="mt-4 font-bold">
|
||||||
Holečkova 106/10, 150 00 Praha 5 - Smíchov 🇨🇿<br/><span class="font-normal"><a href="https://goo.gl/maps/u1aY4RxXMgcm889V7" class="underline hover:no-underline" target="_blank">Google Maps</a>, <a href="https://mapy.cz/s/cuvetubafo" class="underline hover:no-underline" target="_blank">Mapy.cz</a></span>
|
Holečkova 106/10, 150 00 Praha 5 - Smíchov 🇨🇿<br /><span
|
||||||
|
class="font-normal"
|
||||||
|
><a
|
||||||
|
href="https://goo.gl/maps/u1aY4RxXMgcm889V7"
|
||||||
|
class="underline hover:no-underline"
|
||||||
|
target="_blank">Google Maps</a
|
||||||
|
>,
|
||||||
|
<a
|
||||||
|
href="https://mapy.cz/s/cuvetubafo"
|
||||||
|
class="underline hover:no-underline"
|
||||||
|
target="_blank">Mapy.cz</a
|
||||||
|
></span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
Benediktinky. Kulturní památka. Česká Pošta. Poštovní muzeum.
|
Benediktinky. Kulturní památka. Česká Pošta. Poštovní muzeum. Na první
|
||||||
Na první pohled nesouvisející názvy, které jsou ale neodmyslitelnou součástí unikátního komplexu Gabriel Loci na pražském Smíchově doslova pár minut od centra.
|
pohled nesouvisející názvy, které jsou ale neodmyslitelnou součástí
|
||||||
Na konci 19.století v klášteře sídlily řeholnice, ženské opatství řádu benediktinek beuronské kongregace. Později prostory spravovalo československé Ministerstvo pošt a telegrafů.
|
unikátního komplexu Gabriel Loci na pražském Smíchově doslova pár
|
||||||
Dnes komplex využívají hlavně natáčecí studia jako HBO, Netflix nebo i ČT. No a my! 💪<br/><br/>
|
minut od centra. Na konci 19.století v klášteře sídlily řeholnice,
|
||||||
Zažijte mysteriózní atmosféru komplexu na 1.ročníku konference UTXO.22. Část after-party si užijete doslova v pitevně ze seriálu Devadesátky 👌😀
|
ženské opatství řádu benediktinek beuronské kongregace. Později
|
||||||
|
prostory spravovalo československé Ministerstvo pošt a telegrafů. Dnes
|
||||||
|
komplex využívají hlavně natáčecí studia jako HBO, Netflix nebo i ČT.
|
||||||
|
No a my! 💪<br /><br />
|
||||||
|
Zažijte mysteriózní atmosféru komplexu na 1.ročníku konference UTXO.22.
|
||||||
|
Část after-party si užijete doslova v pitevně ze seriálu Devadesátky 👌😀
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -96,23 +162,60 @@ Zažijte mysteriózní atmosféru komplexu na 1.ročníku konference UTXO.22. Č
|
||||||
<div class="text-2xl uppercase font-bold">Partneři</div>
|
<div class="text-2xl uppercase font-bold">Partneři</div>
|
||||||
<div class="mt-6">Sponzoři</div>
|
<div class="mt-6">Sponzoři</div>
|
||||||
<div class="mt-6 flex flex-wrap gap-8 justify-left">
|
<div class="mt-6 flex flex-wrap gap-8 justify-left">
|
||||||
{#each $bundle.spec.partners.filter(p => p.type === 'sponsor') as p}
|
{#each $bundle.spec.partners.filter((p) => p.type === "sponsor") as p}
|
||||||
<div class="w-28">
|
<div class="w-28">
|
||||||
<a href={p.web.url} target="_blank"><Avatar speaker={p} col="partners" size="custom" customSize="w-24 shadow-xl" /></a>
|
<a href={p.web.url} target="_blank"
|
||||||
|
><Avatar
|
||||||
|
speaker={p}
|
||||||
|
col="partners"
|
||||||
|
size="custom"
|
||||||
|
customSize="w-24 shadow-xl"
|
||||||
|
/></a
|
||||||
|
>
|
||||||
<div class="text-center text-sm uppercase font-bold">{p.name}</div>
|
<div class="text-center text-sm uppercase font-bold">{p.name}</div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-10">Komunity</div>
|
<div class="mt-10">Komunity</div>
|
||||||
<div class="mt-6 flex flex-wrap gap-6 justify-left">
|
<div class="mt-6 flex flex-wrap gap-6 justify-left">
|
||||||
{#each $bundle.spec.partners.filter(p => p.type === 'community') as p}
|
{#each $bundle.spec.partners.filter((p) => p.type === "community") as p}
|
||||||
<div><a href={p.web ? p.web.url : (p.twitter ? `https://twitter.com/${p.twitter}` : '')} target="_blank"><Avatar speaker={p} col="partners" size="custom" customSize="w-20 shadow-lg" /></a></div>
|
<div>
|
||||||
|
<a
|
||||||
|
href={p.web
|
||||||
|
? p.web.url
|
||||||
|
: p.twitter
|
||||||
|
? `https://twitter.com/${p.twitter}`
|
||||||
|
: ""}
|
||||||
|
target="_blank"
|
||||||
|
><Avatar
|
||||||
|
speaker={p}
|
||||||
|
col="partners"
|
||||||
|
size="custom"
|
||||||
|
customSize="w-20 shadow-lg"
|
||||||
|
/></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-10">Mediální partneři</div>
|
<div class="mt-10">Mediální partneři</div>
|
||||||
<div class="mt-6 flex flex-wrap gap-4 justify-left">
|
<div class="mt-6 flex flex-wrap gap-4 justify-left">
|
||||||
{#each $bundle.spec.partners.filter(p => p.type === 'medium') as p}
|
{#each $bundle.spec.partners.filter((p) => p.type === "medium") as p}
|
||||||
<div><a href={p.web ? p.web.url : (p.twitter ? `https://twitter.com/${p.twitter}` : '')} target="_blank"><Avatar speaker={p} col="partners" size="custom" customSize="w-16 shadow-lg" /></a></div>
|
<div>
|
||||||
|
<a
|
||||||
|
href={p.web
|
||||||
|
? p.web.url
|
||||||
|
: p.twitter
|
||||||
|
? `https://twitter.com/${p.twitter}`
|
||||||
|
: ""}
|
||||||
|
target="_blank"
|
||||||
|
><Avatar
|
||||||
|
speaker={p}
|
||||||
|
col="partners"
|
||||||
|
size="custom"
|
||||||
|
customSize="w-16 shadow-lg"
|
||||||
|
/></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -124,9 +227,11 @@ Zažijte mysteriózní atmosféru komplexu na 1.ročníku konference UTXO.22. Č
|
||||||
<h2 class="uppercase pt-5" id="faq">Často kladené dotazy (FAQ)</h2>
|
<h2 class="uppercase pt-5" id="faq">Často kladené dotazy (FAQ)</h2>
|
||||||
<div class="md:columns-2 columns-1 mt-8 h-auto">
|
<div class="md:columns-2 columns-1 mt-8 h-auto">
|
||||||
{#each $bundle.spec.faqs as item}
|
{#each $bundle.spec.faqs as item}
|
||||||
<div class="mb-5 break-inside-avoid-column bg-blue-100/60 rounded-xl px-8 py-6 text-left transition-all box-shadow-light overflow-visible">
|
<div
|
||||||
|
class="mb-5 break-inside-avoid-column bg-blue-100/60 rounded-xl px-8 py-6 text-left transition-all box-shadow-light overflow-visible"
|
||||||
|
>
|
||||||
<div class="mb-4 font-bold">{item.question}</div>
|
<div class="mb-4 font-bold">{item.question}</div>
|
||||||
<SvelteMarkdown source={item.answer} renderers={renderers} />
|
<SvelteMarkdown source={item.answer} {renderers} />
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,47 +3,49 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { goto } from "$app/navigation";
|
||||||
|
import Avatar from "$lib/Avatar.svelte";
|
||||||
|
import Event from "$lib/Event.svelte";
|
||||||
|
import { onMount, beforeUpdate } from "svelte";
|
||||||
|
import { page } from "$app/stores";
|
||||||
|
import { bundle } from "$lib/stores.js";
|
||||||
|
import SvelteMarkdown from "svelte-markdown";
|
||||||
|
import Link from "$lib/Link.svelte";
|
||||||
|
const renderers = { link: Link };
|
||||||
|
|
||||||
import { goto } from '$app/navigation';
|
$: id = getId($page.url.search);
|
||||||
import Avatar from '$lib/Avatar.svelte';
|
$: s = $bundle ? $bundle.spec.speakers.find((s) => s.id === id) : null;
|
||||||
import Event from '$lib/Event.svelte';
|
$: events = s
|
||||||
import { onMount, beforeUpdate } from 'svelte';
|
? $bundle.spec.events.filter(
|
||||||
import { page } from '$app/stores';
|
(ev) => ev.speakers && ev.speakers.includes(s.id)
|
||||||
import { bundle } from '$lib/stores.js';
|
)
|
||||||
import SvelteMarkdown from 'svelte-markdown';
|
: [];
|
||||||
import Link from '$lib/Link.svelte';
|
|
||||||
const renderers = { link: Link }
|
|
||||||
|
|
||||||
$: id = getId($page.url.search)
|
|
||||||
$: s = $bundle ? $bundle.spec.speakers.find(s => s.id === id) : null
|
|
||||||
$: events = s ? $bundle.spec.events.filter(ev => ev.speakers && ev.speakers.includes(s.id)) : []
|
|
||||||
|
|
||||||
function getId(search) {
|
function getId(search) {
|
||||||
const searchParams = new URLSearchParams(search)
|
const searchParams = new URLSearchParams(search);
|
||||||
const cid = searchParams.get('id')
|
const cid = searchParams.get("id");
|
||||||
if (!$bundle.spec.speakers.find(s => s.id === cid)) {
|
if (!$bundle.spec.speakers.find((s) => s.id === cid)) {
|
||||||
goto('/')
|
goto("/");
|
||||||
}
|
}
|
||||||
return cid
|
return cid;
|
||||||
}
|
}
|
||||||
|
|
||||||
function trackRender(trackId) {
|
function trackRender(trackId) {
|
||||||
const track = $bundle.spec.tracks.find(t => t.id === trackId)
|
const track = $bundle.spec.tracks.find((t) => t.id === trackId);
|
||||||
return track.shortname || track.name
|
return track.shortname || track.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFlagEmoji(countryCode) {
|
function getFlagEmoji(countryCode) {
|
||||||
const codePoints = countryCode
|
const codePoints = countryCode
|
||||||
.toUpperCase()
|
.toUpperCase()
|
||||||
.split('')
|
.split("")
|
||||||
.map(char => 127397 + char.charCodeAt());
|
.map((char) => 127397 + char.charCodeAt());
|
||||||
return String.fromCodePoint(...codePoints);
|
return String.fromCodePoint(...codePoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>{s ? s.name : ''} | Lidé | {$bundle ? $bundle.name : 'UTXO.22'}</title>
|
<title>{s ? s.name : ""} | Lidé | {$bundle ? $bundle.name : "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 class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl text-blue-web">
|
||||||
|
@ -54,29 +56,54 @@
|
||||||
<div class="mb-4 text-md uppercase">Přednášející</div>
|
<div class="mb-4 text-md uppercase">Přednášející</div>
|
||||||
<h1 class="text-2xl font-bold">{s.name} {getFlagEmoji(s.country)}</h1>
|
<h1 class="text-2xl font-bold">{s.name} {getFlagEmoji(s.country)}</h1>
|
||||||
{#if s.nickname}
|
{#if s.nickname}
|
||||||
<div class="mt-1"><span class="text-xs">aka</span> <span class="font-bold">{s.nickname}</span></div>
|
<div class="mt-1">
|
||||||
|
<span class="text-xs">aka</span>
|
||||||
|
<span class="font-bold">{s.nickname}</span>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if s.bio}
|
{#if s.bio}
|
||||||
<div class="mt-4 text-blue-web italic"><SvelteMarkdown source={s.bio} renderers={renderers} /></div>
|
<div class="mt-4 text-blue-web italic">
|
||||||
|
<SvelteMarkdown source={s.bio} {renderers} />
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if s.orgs}
|
{#if s.orgs}
|
||||||
<div class="mt-4 text-blue-web links"><SvelteMarkdown source={s.orgs} renderers={renderers} /></div>
|
<div class="mt-4 text-blue-web links">
|
||||||
|
<SvelteMarkdown source={s.orgs} {renderers} />
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="mt-4">Sekce: {s.tracks.map(t => trackRender(t)).join(', ')}</div>
|
<div class="mt-4">
|
||||||
|
Sekce: {s.tracks.map((t) => trackRender(t)).join(", ")}
|
||||||
|
</div>
|
||||||
{#if s.twitter}
|
{#if s.twitter}
|
||||||
<div class="mt-2">Twitter: <a href="https://twitter.com/{s.twitter}" target="_blank" class="font-bold">@{s.twitter}</a></div>
|
<div class="mt-2">
|
||||||
|
Twitter: <a
|
||||||
|
href="https://twitter.com/{s.twitter}"
|
||||||
|
target="_blank"
|
||||||
|
class="font-bold">@{s.twitter}</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if s.linkedin}
|
{#if s.linkedin}
|
||||||
<div class="mt-2">LinkedIn: <a href="https://linkedin.com/in/{s.twitter}" target="_blank" class="font-bold">@{s.linkedin}</a></div>
|
<div class="mt-2">
|
||||||
|
LinkedIn: <a
|
||||||
|
href="https://linkedin.com/in/{s.twitter}"
|
||||||
|
target="_blank"
|
||||||
|
class="font-bold">@{s.linkedin}</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if s.web && s.web.url}
|
{#if s.web && s.web.url}
|
||||||
<div class="mt-2">Web: <a href="{s.web.url}" target="_blank" class="font-bold">{s.web.name || s.web.url.replace(/^https?:\/\//, '')}</a></div>
|
<div class="mt-2">
|
||||||
|
Web: <a href={s.web.url} target="_blank" class="font-bold"
|
||||||
|
>{s.web.name || s.web.url.replace(/^https?:\/\//, "")}</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if s.desc}
|
{#if s.desc}
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<SvelteMarkdown source={s.desc} renderers={renderers} />
|
<SvelteMarkdown source={s.desc} {renderers} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
|
|
|
@ -3,22 +3,23 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Event from '$lib/Event.svelte';
|
import Event from "$lib/Event.svelte";
|
||||||
import { bundle, userData } from '$lib/stores.js';
|
import { bundle, userData } from "$lib/stores.js";
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<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 class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl text-blue-web">
|
||||||
<h1 class="uppercase text-2xl font-bold">Program</h1>
|
<h1 class="uppercase text-2xl font-bold">Program</h1>
|
||||||
<div class="mt-2 text-sm">Program stále připravujeme. Jeho konečná podoba bude zveřejněna pár týdnů před konferencí.</div>
|
<div class="mt-2 text-sm">
|
||||||
|
Program stále připravujeme. Jeho konečná podoba bude zveřejněna pár týdnů
|
||||||
|
před konferencí.
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
{#each $bundle.spec.events.filter(e => !e.parent) as e}
|
{#each $bundle.spec.events.filter((e) => !e.parent) as e}
|
||||||
<Event event={e} />
|
<Event event={e} />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,45 +3,46 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { page } from '$app/stores';
|
import { page } from "$app/stores";
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from "$app/navigation";
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from "svelte";
|
||||||
import { bundle, userData } from '$lib/stores.js';
|
import { bundle, userData } from "$lib/stores.js";
|
||||||
import EventTypeLabel from '$lib/EventTypeLabel.svelte';
|
import EventTypeLabel from "$lib/EventTypeLabel.svelte";
|
||||||
import Avatar from '$lib/Avatar.svelte';
|
import Avatar from "$lib/Avatar.svelte";
|
||||||
import SvelteMarkdown from 'svelte-markdown';
|
import SvelteMarkdown from "svelte-markdown";
|
||||||
import Link from '$lib/Link.svelte';
|
import Link from "$lib/Link.svelte";
|
||||||
|
|
||||||
const renderers = { link: Link }
|
const renderers = { link: Link };
|
||||||
|
|
||||||
$: 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;
|
||||||
|
|
||||||
function getId(search) {
|
function getId(search) {
|
||||||
const searchParams = new URLSearchParams(search)
|
const searchParams = new URLSearchParams(search);
|
||||||
const cid = searchParams.get('id')
|
const cid = searchParams.get("id");
|
||||||
if (!$bundle.spec.events.find(s => s.id === cid)) {
|
if (!$bundle.spec.events.find((s) => s.id === cid)) {
|
||||||
goto('/')
|
goto("/");
|
||||||
}
|
}
|
||||||
return cid
|
return cid;
|
||||||
}
|
}
|
||||||
|
|
||||||
function speakersMap(arr) {
|
function speakersMap(arr) {
|
||||||
if (!arr) return;
|
if (!arr) return;
|
||||||
return arr.map(sId => {
|
return arr.map((sId) => {
|
||||||
return $bundle.spec.speakers.find(sp => sp.id === sId)
|
return $bundle.spec.speakers.find((sp) => sp.id === sId);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function trackRender(trackId) {
|
function trackRender(trackId) {
|
||||||
const track = $bundle.spec.tracks.find(t => t.id === trackId)
|
const track = $bundle.spec.tracks.find((t) => t.id === trackId);
|
||||||
return track.shortname || track.name
|
return track.shortname || track.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>{e ? e.name : ''} | Události | {$bundle ? $bundle.name : 'UTXO.22'}</title>
|
<title
|
||||||
|
>{e ? e.name : ""} | Události | {$bundle ? $bundle.name : "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 class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl text-blue-web">
|
||||||
|
@ -56,15 +57,17 @@
|
||||||
<div class="mt-4 mb-2 flex flex-wrap gap-4">
|
<div class="mt-4 mb-2 flex flex-wrap gap-4">
|
||||||
{#each speakersMap(e.speakers) as s}
|
{#each speakersMap(e.speakers) as s}
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<Avatar speaker={s} size='semi-small' />
|
<Avatar speaker={s} size="semi-small" />
|
||||||
<div class="m-auto"><a href="/lide?id={s.id}" class="text-xl">{s.name}</a></div>
|
<div class="m-auto">
|
||||||
|
<a href="/lide?id={s.id}" class="text-xl">{s.name}</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="mt-8">
|
<div class="mt-8">
|
||||||
{#if e.description}
|
{#if e.description}
|
||||||
<SvelteMarkdown source={e.description} renderers={renderers}/>
|
<SvelteMarkdown source={e.description} {renderers} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -3,268 +3,299 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { onMount, onDestroy } from 'svelte';
|
import { onMount, onDestroy } from "svelte";
|
||||||
import { faker } from '@faker-js/faker';
|
import { faker } from "@faker-js/faker";
|
||||||
import { orderTicketForm, apiStatus, userData, userDataLocal } from '$lib/stores';
|
import {
|
||||||
|
orderTicketForm,
|
||||||
|
apiStatus,
|
||||||
|
userData,
|
||||||
|
userDataLocal,
|
||||||
|
} from "$lib/stores";
|
||||||
//import btcPay from 'https://btcpay.utxo.cz/modal/btcpay.js';
|
//import btcPay from 'https://btcpay.utxo.cz/modal/btcpay.js';
|
||||||
import api from '$lib/api.js';
|
import api from "$lib/api.js";
|
||||||
import makeBlockie from 'ethereum-blockies-base64';
|
import makeBlockie from "ethereum-blockies-base64";
|
||||||
import { format, formatDistanceToNow } from 'date-fns';
|
import { format, formatDistanceToNow } from "date-fns";
|
||||||
import { cs } from 'date-fns/locale/index.js'
|
import { cs } from "date-fns/locale/index.js";
|
||||||
|
|
||||||
import { page } from '$app/stores';
|
import { page } from "$app/stores";
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from "$app/navigation";
|
||||||
import { loadOrders, loadApiStatus } from '$lib/orders';
|
import { loadOrders, loadApiStatus } from "$lib/orders";
|
||||||
|
|
||||||
const orderTicketFormLS = localStorage.getItem('orderTicketForm')
|
const orderTicketFormLS = localStorage.getItem("orderTicketForm");
|
||||||
let parsed = JSON.parse(orderTicketFormLS)
|
let parsed = JSON.parse(orderTicketFormLS);
|
||||||
if (parsed && parsed.__v === $orderTicketForm.__v) {
|
if (parsed && parsed.__v === $orderTicketForm.__v) {
|
||||||
orderTicketForm.set(parsed)
|
orderTicketForm.set(parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
let forceShow = false
|
let forceShow = false;
|
||||||
let loading = true
|
let loading = true;
|
||||||
let formProcessing = false
|
let formProcessing = false;
|
||||||
$: showOrder = !(($userDataLocal.orders && $userDataLocal.orders.length > 0) || ($userDataLocal.tickets && $userDataLocal.tickets.length > 0))
|
$: showOrder = !(
|
||||||
$: orders = $userDataLocal.orders
|
($userDataLocal.orders && $userDataLocal.orders.length > 0) ||
|
||||||
$: tickets = $userDataLocal.tickets
|
($userDataLocal.tickets && $userDataLocal.tickets.length > 0)
|
||||||
|
);
|
||||||
|
$: orders = $userDataLocal.orders;
|
||||||
|
$: tickets = $userDataLocal.tickets;
|
||||||
|
|
||||||
|
let periodic15 = null;
|
||||||
let periodic15 = null
|
let periodic60 = null;
|
||||||
let periodic60 = null
|
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
|
const sp = $page.url.searchParams;
|
||||||
const sp = $page.url.searchParams
|
if (sp.get("done")) {
|
||||||
if (sp.get('done')) {
|
goto("/gratulujeme");
|
||||||
goto('/gratulujeme');
|
|
||||||
}
|
}
|
||||||
if (sp.get('id') && sp.get('secret')) {
|
if (sp.get("id") && sp.get("secret")) {
|
||||||
userData.update(ud => {
|
userData.update((ud) => {
|
||||||
if (!ud.tickets) ud.tickets = [];
|
if (!ud.tickets) ud.tickets = [];
|
||||||
ud.tickets.push([ sp.get('id'), sp.get('secret') ].join(':'))
|
ud.tickets.push([sp.get("id"), sp.get("secret")].join(":"));
|
||||||
return ud
|
return ud;
|
||||||
})
|
});
|
||||||
await loadOrders($userData)
|
await loadOrders($userData);
|
||||||
goto('/vstupenky');
|
goto("/vstupenky");
|
||||||
}
|
}
|
||||||
loading = false
|
loading = false;
|
||||||
|
|
||||||
periodic15 = setInterval(() => {
|
periodic15 = setInterval(() => {
|
||||||
loadApiStatus()
|
loadApiStatus();
|
||||||
}, 15 * 1000)
|
}, 15 * 1000);
|
||||||
|
|
||||||
periodic60 = setInterval(() => {
|
periodic60 = setInterval(() => {
|
||||||
loadOrders($userData)
|
loadOrders($userData);
|
||||||
}, 60 * 1000)
|
}, 60 * 1000);
|
||||||
})
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
clearInterval(periodic15)
|
clearInterval(periodic15);
|
||||||
clearInterval(periodic60)
|
clearInterval(periodic60);
|
||||||
})
|
});
|
||||||
|
|
||||||
faker.locale = 'cz';
|
faker.locale = "cz";
|
||||||
let orderError = null
|
let orderError = null;
|
||||||
|
|
||||||
$: count = $apiStatus ? [...Array($apiStatus.config.maxTickets).keys()].map(i => i+1) : [];
|
$: count = $apiStatus
|
||||||
|
? [...Array($apiStatus.config.maxTickets).keys()].map((i) => i + 1)
|
||||||
|
: [];
|
||||||
|
|
||||||
function selectPaymentMethod(el) {
|
function selectPaymentMethod(el) {
|
||||||
orderTicketForm.update(f => {
|
orderTicketForm.update((f) => {
|
||||||
f.paymentMethod = el.target.value
|
f.paymentMethod = el.target.value;
|
||||||
return f
|
return f;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function ticketFormCountArray(count) {
|
function ticketFormCountArray(count) {
|
||||||
return [...Array(count).keys()].map(i => i)
|
return [...Array(count).keys()].map((i) => i);
|
||||||
}
|
}
|
||||||
|
|
||||||
function processOrderError(error) {
|
function processOrderError(error) {
|
||||||
if (typeof error === 'string') {
|
if (typeof error === "string") {
|
||||||
return { title: error }
|
return { title: error };
|
||||||
}
|
}
|
||||||
const out = { title: error.title }
|
const out = { title: error.title };
|
||||||
if (error.formErrors && error.formErrors.length > 0) {
|
if (error.formErrors && error.formErrors.length > 0) {
|
||||||
let suberrs = []
|
let suberrs = [];
|
||||||
if (error.formErrors.find(fe => fe.instancePath === '/email')) {
|
if (error.formErrors.find((fe) => fe.instancePath === "/email")) {
|
||||||
suberrs.push(`Neplatný email`)
|
suberrs.push(`Neplatný email`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ticket = null
|
let ticket = null;
|
||||||
if (error.formErrors.find(fe => ticket = fe.instancePath.match(/\/tickets\/(\d+)\/twitter/))) {
|
if (
|
||||||
suberrs.push(`Neplatný Twitter účet (Vstupenka #${Number(ticket[1])+1}).`)
|
error.formErrors.find(
|
||||||
|
(fe) => (ticket = fe.instancePath.match(/\/tickets\/(\d+)\/twitter/))
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
suberrs.push(
|
||||||
|
`Neplatný Twitter účet (Vstupenka #${Number(ticket[1]) + 1}).`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
out.title = 'Nesprávně vyplněný formulář: ' + (suberrs.length > 0 ? suberrs.join(',') : 'neznámá chyba')
|
out.title =
|
||||||
out.debug = error.formErrors
|
"Nesprávně vyplněný formulář: " +
|
||||||
|
(suberrs.length > 0 ? suberrs.join(",") : "neznámá chyba");
|
||||||
|
out.debug = error.formErrors;
|
||||||
}
|
}
|
||||||
if (!out.title) {
|
if (!out.title) {
|
||||||
out.title = 'Neznámá chyba, zkuste to prosím později.'
|
out.title = "Neznámá chyba, zkuste to prosím později.";
|
||||||
}
|
}
|
||||||
console.log(out)
|
console.log(out);
|
||||||
return out
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitOrderHandler() {
|
async function submitOrderHandler() {
|
||||||
// order process
|
// order process
|
||||||
formProcessing = true
|
formProcessing = true;
|
||||||
|
|
||||||
// clean previous errors
|
// clean previous errors
|
||||||
$: orderError = null
|
$: orderError = null;
|
||||||
|
|
||||||
const cloned = Object.assign({}, $orderTicketForm)
|
const cloned = Object.assign({}, $orderTicketForm);
|
||||||
cloned.tipCustom = Number(cloned.tipCustom)
|
cloned.tipCustom = Number(cloned.tipCustom);
|
||||||
cloned.totalPrice = totalPrice
|
cloned.totalPrice = totalPrice;
|
||||||
const resp = await api.submitOrder(cloned)
|
const resp = await api.submitOrder(cloned);
|
||||||
|
|
||||||
if (resp.error) {
|
if (resp.error) {
|
||||||
$: orderError = processOrderError(resp.error)
|
$: orderError = processOrderError(resp.error);
|
||||||
formProcessing = false
|
formProcessing = false;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!resp.ok || !resp.payment.url) {
|
if (!resp.ok || !resp.payment.url) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset tickets in form
|
// reset tickets in form
|
||||||
orderTicketForm.update(of => {
|
orderTicketForm.update((of) => {
|
||||||
of.count = 1
|
of.count = 1;
|
||||||
of.tickets = []
|
of.tickets = [];
|
||||||
return of
|
return of;
|
||||||
})
|
});
|
||||||
|
|
||||||
// add order to user data
|
// add order to user data
|
||||||
userData.update(ud => {
|
userData.update((ud) => {
|
||||||
if (!ud.orders) {
|
if (!ud.orders) {
|
||||||
ud.orders = []
|
ud.orders = [];
|
||||||
}
|
}
|
||||||
ud.orders.push(resp.orderId)
|
ud.orders.push(resp.orderId);
|
||||||
return ud
|
return ud;
|
||||||
})
|
});
|
||||||
|
|
||||||
window.location.replace(resp.payment.url)
|
window.location.replace(resp.payment.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ticketsNum = 0
|
let ticketsNum = 0;
|
||||||
|
|
||||||
orderTicketForm.subscribe(f => {
|
orderTicketForm.subscribe((f) => {
|
||||||
if (f.count !== ticketsNum) {
|
if (f.count !== ticketsNum) {
|
||||||
ticketsNum = f.count
|
ticketsNum = f.count;
|
||||||
orderTicketForm.update(cf => {
|
orderTicketForm.update((cf) => {
|
||||||
f.tickets = f.tickets.slice(0, f.count)
|
f.tickets = f.tickets.slice(0, f.count);
|
||||||
for (let i = 0; i < f.count; i++) {
|
for (let i = 0; i < f.count; i++) {
|
||||||
console.log(i)
|
console.log(i);
|
||||||
if (!f.tickets[i]) {
|
if (!f.tickets[i]) {
|
||||||
f.tickets[i] = { name: '', org: '', twitter: '', extras: { kino: false } }
|
f.tickets[i] = {
|
||||||
|
name: "",
|
||||||
|
org: "",
|
||||||
|
twitter: "",
|
||||||
|
extras: { kino: false },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return f
|
return f;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
localStorage.setItem('orderTicketForm', JSON.stringify(f))
|
localStorage.setItem("orderTicketForm", JSON.stringify(f));
|
||||||
})
|
});
|
||||||
|
|
||||||
function changeTip(perc) {
|
function changeTip(perc) {
|
||||||
return () => {
|
return () => {
|
||||||
orderTicketForm.update(of => {
|
orderTicketForm.update((of) => {
|
||||||
of.tipPercent = perc
|
of.tipPercent = perc;
|
||||||
of.tipCustom = ''
|
of.tipCustom = "";
|
||||||
return of
|
return of;
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
orderTicketForm.subscribe(of => {
|
orderTicketForm.subscribe((of) => {
|
||||||
const val = Number(of.tipCustom)
|
const val = Number(of.tipCustom);
|
||||||
if (val === NaN || !val || val < 1 || !String(val).match(/^\d+$/)) {
|
if (val === NaN || !val || val < 1 || !String(val).match(/^\d+$/)) {
|
||||||
of.tipCustom = ''
|
of.tipCustom = "";
|
||||||
}
|
} else if (val && val > 0 && of.tipPercent > 0) {
|
||||||
else if (val && val > 0 && of.tipPercent > 0) {
|
of.tipPercent = 0;
|
||||||
of.tipPercent = 0
|
|
||||||
}
|
}
|
||||||
if (orderError) {
|
if (orderError) {
|
||||||
orderError = false
|
orderError = false;
|
||||||
}
|
}
|
||||||
return of
|
return of;
|
||||||
})
|
});
|
||||||
|
|
||||||
function roundPrice(num) {
|
function roundPrice(num) {
|
||||||
return Math.round(num * 100) / 100
|
return Math.round(num * 100) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
function extrasStatsRender(form) {
|
function extrasStatsRender(form) {
|
||||||
let obj = {}
|
let obj = {};
|
||||||
$apiStatus.config.extras.forEach(ex => {
|
$apiStatus.config.extras.forEach((ex) => {
|
||||||
obj[ex.id] = { count: 0, sum: 0, price: ex.price }
|
obj[ex.id] = { count: 0, sum: 0, price: ex.price };
|
||||||
form.tickets.forEach(t => {
|
form.tickets.forEach((t) => {
|
||||||
if (t.extras[ex.id]) {
|
if (t.extras[ex.id]) {
|
||||||
obj[ex.id].count++
|
obj[ex.id].count++;
|
||||||
obj[ex.id].sum = obj[ex.id].count * ex.price
|
obj[ex.id].sum = obj[ex.id].count * ex.price;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
let arr = Object.keys(obj).map(key => Object.assign({ id: key }, obj[key]))
|
let arr = Object.keys(obj).map((key) =>
|
||||||
|
Object.assign({ id: key }, obj[key])
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
sum: arr.reduce((p, c) => p + c.sum, 0),
|
sum: arr.reduce((p, c) => p + c.sum, 0),
|
||||||
arr
|
arr,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
$: extrasStats = $apiStatus ? extrasStatsRender($orderTicketForm) : {}
|
$: extrasStats = $apiStatus ? extrasStatsRender($orderTicketForm) : {};
|
||||||
$: ticketPrice = $apiStatus && $apiStatus.wave ? $orderTicketForm.count * $apiStatus.wave.price : 0
|
$: ticketPrice =
|
||||||
$: totalBeforeTip = ticketPrice + extrasStats.sum
|
$apiStatus && $apiStatus.wave
|
||||||
$: tip = roundPrice($orderTicketForm.tipPercent > 0 ? $orderTicketForm.tipPercent * (totalBeforeTip/100) : Number($orderTicketForm.tipCustom))
|
? $orderTicketForm.count * $apiStatus.wave.price
|
||||||
$: totalPrice = totalBeforeTip + tip
|
: 0;
|
||||||
|
$: totalBeforeTip = ticketPrice + extrasStats.sum;
|
||||||
|
$: tip = roundPrice(
|
||||||
|
$orderTicketForm.tipPercent > 0
|
||||||
|
? $orderTicketForm.tipPercent * (totalBeforeTip / 100)
|
||||||
|
: Number($orderTicketForm.tipCustom)
|
||||||
|
);
|
||||||
|
$: totalPrice = totalBeforeTip + tip;
|
||||||
|
|
||||||
const orderStatuses = {
|
const orderStatuses = {
|
||||||
new: {
|
new: {
|
||||||
name: 'Čeká na platbu',
|
name: "Čeká na platbu",
|
||||||
icon: 'fa-solid fa-clock',
|
icon: "fa-solid fa-clock",
|
||||||
color: 'text-yellow-600',
|
color: "text-yellow-600",
|
||||||
text: (o) => {
|
text: (o) => {
|
||||||
return 'Tato objednávka čeká na platbu'
|
return "Tato objednávka čeká na platbu";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
done: {
|
done: {
|
||||||
name: 'Zaplacená',
|
name: "Zaplacená",
|
||||||
icon: 'fa-solid fa-check',
|
icon: "fa-solid fa-check",
|
||||||
color: 'text-green-600'
|
color: "text-green-600",
|
||||||
},
|
},
|
||||||
cancelled: {
|
cancelled: {
|
||||||
name: 'Zrušená',
|
name: "Zrušená",
|
||||||
icon: 'fa-solid fa-ban',
|
icon: "fa-solid fa-ban",
|
||||||
color: 'text-gray-600'
|
color: "text-gray-600",
|
||||||
},
|
},
|
||||||
expired: {
|
expired: {
|
||||||
name: 'Expirovaná',
|
name: "Expirovaná",
|
||||||
icon: 'fa-solid fa-clock',
|
icon: "fa-solid fa-clock",
|
||||||
color: 'text-gray-600'
|
color: "text-gray-600",
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
async function orderActionHandler(id, action) {
|
async function orderActionHandler(id, action) {
|
||||||
const resp = await api.apiCall('updateOrder', { method: 'POST' }, { id, action })
|
const resp = await api.apiCall(
|
||||||
loadOrders($userData)
|
"updateOrder",
|
||||||
loadApiStatus()
|
{ method: "POST" },
|
||||||
|
{ id, action }
|
||||||
|
);
|
||||||
|
loadOrders($userData);
|
||||||
|
loadApiStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeOrder(id) {
|
function removeOrder(id) {
|
||||||
userData.update(ud => {
|
userData.update((ud) => {
|
||||||
console.log('change', ud.orders, id)
|
console.log("change", ud.orders, id);
|
||||||
let index = ud.orders.indexOf(id)
|
let index = ud.orders.indexOf(id);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
if (ud.orders.length === 1) {
|
if (ud.orders.length === 1) {
|
||||||
ud.orders = []
|
ud.orders = [];
|
||||||
} else {
|
} else {
|
||||||
ud.orders.splice(index, 1)
|
ud.orders.splice(index, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ud
|
return ud;
|
||||||
})
|
});
|
||||||
loadOrders($userData)
|
loadOrders($userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
@ -281,21 +312,37 @@
|
||||||
<div class="mt-4 flex flex-wrap gap-3">
|
<div class="mt-4 flex flex-wrap gap-3">
|
||||||
{#each tickets as ticket}
|
{#each tickets as ticket}
|
||||||
<div class="w-full sm:w-80">
|
<div class="w-full sm:w-80">
|
||||||
<div class="h-2 bg-blue-web rounded-t-md shadow-md"></div>
|
<div class="h-2 bg-blue-web rounded-t-md shadow-md" />
|
||||||
<div class="border-l border-b border-r p-4 rounded-b-md shadow-md border-blue-web">
|
<div
|
||||||
|
class="border-l border-b border-r p-4 rounded-b-md shadow-md border-blue-web"
|
||||||
|
>
|
||||||
<div class="flex gap-3 text-sm">
|
<div class="flex gap-3 text-sm">
|
||||||
<div class="w-11 h-11 rounded-md" style="background-image: url({makeBlockie(ticket.avatarHash)}); background-size: 100% 100%;"></div>
|
<div
|
||||||
|
class="w-11 h-11 rounded-md"
|
||||||
|
style="background-image: url({makeBlockie(
|
||||||
|
ticket.avatarHash
|
||||||
|
)}); background-size: 100% 100%;"
|
||||||
|
/>
|
||||||
<div class="w-auto">
|
<div class="w-auto">
|
||||||
<div class="no-flex">
|
<div class="no-flex">
|
||||||
<span class="px-2 py-1 bg-blue-web text-white rounded w-auto">#{ticket.id}</span>
|
<span
|
||||||
|
class="px-2 py-1 bg-blue-web text-white rounded w-auto"
|
||||||
|
>#{ticket.id}</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1.5">Běžná vstupenka</div>
|
<div class="mt-1.5">Běžná vstupenka</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if ticket.data}
|
{#if ticket.data}
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
{#if ticket.data.name}{ticket.data.name}{:else}<span class="italic">Anonym</span>{/if} {#if ticket.data.org}({ticket.data.org}){/if}
|
{#if ticket.data.name}{ticket.data.name}{:else}<span
|
||||||
{#if ticket.data.twitter}<a href="https://twitter.com/{ticket.data.twitter}" target="_blank"><i class="fa-brands fa-twitter"></i></a>{/if}
|
class="italic">Anonym</span
|
||||||
|
>{/if}
|
||||||
|
{#if ticket.data.org}({ticket.data.org}){/if}
|
||||||
|
{#if ticket.data.twitter}<a
|
||||||
|
href="https://twitter.com/{ticket.data.twitter}"
|
||||||
|
target="_blank"><i class="fa-brands fa-twitter" /></a
|
||||||
|
>{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -313,32 +360,71 @@
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
{#each orders as order}
|
{#each orders as order}
|
||||||
<div class="mb-2 px-3 py-2 border rounded-lg">
|
<div class="mb-2 px-3 py-2 border rounded-lg">
|
||||||
{#if ['expired', 'cancelled'].includes(order.status)}
|
{#if ["expired", "cancelled"].includes(order.status)}
|
||||||
<div class="float-right"><a class="cursor-pointer" on:click={() => removeOrder(order.id)}><i class="fa-solid fa-xmark"></i></a></div>
|
<div class="float-right">
|
||||||
|
<a
|
||||||
|
class="cursor-pointer"
|
||||||
|
on:click={() => removeOrder(order.id)}
|
||||||
|
><i class="fa-solid fa-xmark" /></a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="flex flex-wrap gap-3 text-sm">
|
<div class="flex flex-wrap gap-3 text-sm">
|
||||||
<div class="px-2 py-1 bg-gray-200 rounded">#{order.id}</div>
|
<div class="px-2 py-1 bg-gray-200 rounded">#{order.id}</div>
|
||||||
<div class="my-auto uppercase {orderStatuses[order.status].color ? (orderStatuses[order.status].color) : ''}">
|
<div
|
||||||
|
class="my-auto uppercase {orderStatuses[order.status].color
|
||||||
|
? orderStatuses[order.status].color
|
||||||
|
: ''}"
|
||||||
|
>
|
||||||
{#if orderStatuses[order.status].icon}
|
{#if orderStatuses[order.status].icon}
|
||||||
<i class="{orderStatuses[order.status].icon} mr-0.5"></i>
|
<i class="{orderStatuses[order.status].icon} mr-0.5" />
|
||||||
{/if}
|
{/if}
|
||||||
{orderStatuses[order.status].name}
|
{orderStatuses[order.status].name}
|
||||||
{#if order.status === 'new'}
|
{#if order.status === "new"}
|
||||||
- expirace {format(new Date(order.expiration), 'd.M. H:mm')} (zbývá {formatDistanceToNow(new Date(order.expiration), { locale: cs, includeSeconds: true })})
|
- expirace {format(
|
||||||
|
new Date(order.expiration),
|
||||||
|
"d.M. H:mm"
|
||||||
|
)} (zbývá {formatDistanceToNow(
|
||||||
|
new Date(order.expiration),
|
||||||
|
{ locale: cs, includeSeconds: true }
|
||||||
|
)})
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2 text-sm flex gap-2">
|
<div class="mt-2 text-sm flex gap-2">
|
||||||
<div>Vytvořeno: <span class="font-bold">{format(new Date(order.created), 'd.M.y H:mm')}</span><br/></div>
|
<div>
|
||||||
<div>Částka: <span class="font-bold">{order.amount} Kč</span><br/></div>
|
Vytvořeno: <span class="font-bold"
|
||||||
<div>Platební metoda: <span class="font-bold">{$apiStatus.config.paymentMethods.find(pm => pm.id === order.paymentMethod).shortname}</span></div>
|
>{format(new Date(order.created), "d.M.y H:mm")}</span
|
||||||
|
><br />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Částka: <span class="font-bold">{order.amount} Kč</span><br
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Platební metoda: <span class="font-bold"
|
||||||
|
>{$apiStatus.config.paymentMethods.find(
|
||||||
|
(pm) => pm.id === order.paymentMethod
|
||||||
|
).shortname}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if orderStatuses[order.status].text}
|
{#if orderStatuses[order.status].text}
|
||||||
<div class="mt-2 italic">{orderStatuses[order.status].text(order)}</div>
|
<div class="mt-2 italic">
|
||||||
|
{orderStatuses[order.status].text(order)}
|
||||||
|
</div>
|
||||||
{#if order.actions}
|
{#if order.actions}
|
||||||
<div class="flex gap-3">
|
<div class="flex gap-3">
|
||||||
{#each order.actions as action}
|
{#each order.actions as action}
|
||||||
<div class="mt-2"><a href="{action.url}" class="underline hover:no-underline cursor-pointer" on:click={() => orderActionHandler(order.id, action.remote)}>{action.name}</a></div>
|
<div class="mt-2">
|
||||||
|
<a
|
||||||
|
href={action.url}
|
||||||
|
class="underline hover:no-underline cursor-pointer"
|
||||||
|
on:click={() =>
|
||||||
|
orderActionHandler(order.id, action.remote)}
|
||||||
|
>{action.name}</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -352,45 +438,79 @@
|
||||||
<h1 class="uppercase text-2xl font-bold">Nákup vstupenek</h1>
|
<h1 class="uppercase text-2xl font-bold">Nákup vstupenek</h1>
|
||||||
<div class="mt-4 mb-8">
|
<div class="mt-4 mb-8">
|
||||||
<div class="flex w-full uppercase text-sm mb-2">
|
<div class="flex w-full uppercase text-sm mb-2">
|
||||||
<div class="flex-1">{$apiStatus.wave.name} ({$apiStatus.wave.price} Kč)</div>
|
<div class="flex-1">
|
||||||
<div class="justify-end">Zbývá {$apiStatus.wave.live.left} / {$apiStatus.wave.count}</div>
|
{$apiStatus.wave.name} ({$apiStatus.wave.price} Kč)
|
||||||
|
</div>
|
||||||
|
<div class="justify-end">
|
||||||
|
Zbývá {$apiStatus.wave.live.left} / {$apiStatus.wave.count}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2.5">
|
<div class="w-full bg-gray-200 rounded-full h-2.5">
|
||||||
<div class="bg-utxo-gradient h-2.5 rounded-full transition-all" style="width: {$apiStatus.wave.live.perc}%"></div>
|
<div
|
||||||
|
class="bg-utxo-gradient h-2.5 rounded-full transition-all"
|
||||||
|
style="width: {$apiStatus.wave.live.perc}%"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if $apiStatus.wave.live.left <= 0}
|
{#if $apiStatus.wave.live.left <= 0}
|
||||||
<div class="mt-2">Aktuální vlna je vyprodaná. {#if $apiStatus.wave.live.waiting > 0}Zarezervované a nezaplacené vstupenky ({$apiStatus.wave.live.waiting}) se postupně vrací do prodeje.{/if}</div>
|
<div class="mt-2">
|
||||||
{:else}
|
Aktuální vlna je vyprodaná. {#if $apiStatus.wave.live.waiting > 0}Zarezervované
|
||||||
{#if !showOrder && !forceShow}
|
a nezaplacené vstupenky ({$apiStatus.wave.live.waiting}) se
|
||||||
<div class="mt-4">
|
postupně vrací do prodeje.{/if}
|
||||||
<button class="border rounded-full border-[#E16A61] hover:border-0 hover:p-px hover:bg-utxo-gradient hover:text-white" on:click={() => forceShow = true}><div class="px-6 py-2">Nakoupit další vstupenky</div></button>
|
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else if !showOrder && !forceShow}
|
||||||
{#if !$apiStatus.wave}
|
<div class="mt-4">
|
||||||
|
<button
|
||||||
|
class="border rounded-full border-[#E16A61] hover:border-0 hover:p-px hover:bg-utxo-gradient hover:text-white"
|
||||||
|
on:click={() => (forceShow = true)}
|
||||||
|
><div class="px-6 py-2">Nakoupit další vstupenky</div></button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
{:else if !$apiStatus.wave}
|
||||||
<div class="mt-4">V současné době nelze zakoupit vstupenky.</div>
|
<div class="mt-4">V současné době nelze zakoupit vstupenky.</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="p-3 bg-blue-web-light rounded-md mt-6 text-blue-web shadow-md">
|
<div
|
||||||
|
class="p-3 bg-blue-web-light rounded-md mt-6 text-blue-web shadow-md"
|
||||||
|
>
|
||||||
<div class="sm:m-2 border rounded-md p-4 shadow bg-white mb-6">
|
<div class="sm:m-2 border rounded-md p-4 shadow bg-white mb-6">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
Název akce: <span class="font-bold">UTXO.22</span><br />
|
Název akce: <span class="font-bold">UTXO.22</span><br />
|
||||||
Datum konání: <span class="font-bold">4. - 5. červen 2022</span> (sobota - neděle)<br/>
|
Datum konání: <span class="font-bold">4. - 5. červen 2022</span>
|
||||||
Místo: <span class="font-bold">Gabriel Loci</span>, Praha 5<br/><br/>
|
(sobota - neděle)<br />
|
||||||
Aktuální cena vstupenky: <span class="font-bold">{$apiStatus.wave.price} Kč</span> / osobu ({ $apiStatus.wave.name })
|
Místo: <span class="font-bold">Gabriel Loci</span>, Praha 5<br
|
||||||
|
/><br />
|
||||||
|
Aktuální cena vstupenky:
|
||||||
|
<span class="font-bold">{$apiStatus.wave.price} Kč</span>
|
||||||
|
/ osobu ({$apiStatus.wave.name})
|
||||||
</div>
|
</div>
|
||||||
<div class="md:flex gap-3">
|
<div class="md:flex gap-3">
|
||||||
<div class="md:w-1/2 p-2">
|
<div class="md:w-1/2 p-2">
|
||||||
<div class="font-bold uppercase">✅ Vstupenka obsahuje:</div>
|
<div class="font-bold uppercase">
|
||||||
|
✅ Vstupenka obsahuje:
|
||||||
|
</div>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<div class="mb-2">• přístup na všechny přednášky, workshopy a další události v rámci konference</div>
|
<div class="mb-2">
|
||||||
<div class="mb-2">• platnost oba dva konferenční dny (sobota + neděle)</div>
|
• přístup na všechny přednášky, workshopy a další události
|
||||||
<div class="mb-2">• přístup na <span class="font-bold">UTXO.Party</span> v sobotu večer</div>
|
v rámci konference
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
• platnost oba dva konferenční dny (sobota + neděle)
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
• přístup na <span class="font-bold">UTXO.Party</span> v sobotu
|
||||||
|
večer
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="md:w-1/2 p-2 md:mt-0 mt-3">
|
<div class="md:w-1/2 p-2 md:mt-0 mt-3">
|
||||||
<div class="font-bold uppercase">❌ Vstupenka NEobsahuje:</div>
|
<div class="font-bold uppercase">
|
||||||
|
❌ Vstupenka NEobsahuje:
|
||||||
|
</div>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<div class="mb-2">• jídlo a pití - občerstvení bude možné zakoupit na místě (platba kartou nebo Lightning)</div>
|
<div class="mb-2">
|
||||||
|
• jídlo a pití - občerstvení bude možné zakoupit na místě
|
||||||
|
(platba kartou nebo Lightning)
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -398,49 +518,110 @@
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
<div>
|
<div>
|
||||||
<div class="uppercase text-sm font-bold">Email</div>
|
<div class="uppercase text-sm font-bold">Email</div>
|
||||||
<div class="mt-2 text-sm">Kontaktní email, na který budou zaslány vstupenky.</div>
|
<div class="mt-2 text-sm">
|
||||||
<div class="mt-2"><input type="text" class="border border-blue-web rounded-md p-2 w-full lg:w-1/2 text-blue-web" bind:value={$orderTicketForm.email} /></div>
|
Kontaktní email, na který budou zaslány vstupenky.
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="border border-blue-web rounded-md p-2 w-full lg:w-1/2 text-blue-web"
|
||||||
|
bind:value={$orderTicketForm.email}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<div class="uppercase text-sm font-bold">Počet vstupenek</div>
|
<div class="uppercase text-sm font-bold">Počet vstupenek</div>
|
||||||
<div class="mt-2 flex gap-3">
|
<div class="mt-2 flex gap-3">
|
||||||
<select name="count" class="border border-blue-web rounded-md p-2 text-blue-web bg-white" bind:value={$orderTicketForm.count}>
|
<select
|
||||||
|
name="count"
|
||||||
|
class="border border-blue-web rounded-md p-2 text-blue-web bg-white"
|
||||||
|
bind:value={$orderTicketForm.count}
|
||||||
|
>
|
||||||
{#each count as i}
|
{#each count as i}
|
||||||
<option value={i}>{i}</option>
|
<option value={i}>{i}</option>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
<div class="my-auto">
|
<div class="my-auto">
|
||||||
× <span class="font-bold">{$apiStatus.wave.price} Kč</span> (cena vstupenky)
|
× <span class="font-bold">{$apiStatus.wave.price} Kč</span> (cena
|
||||||
|
vstupenky)
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<div class="uppercase text-sm font-bold">Vstupenky a příplatky</div>
|
<div class="uppercase text-sm font-bold">
|
||||||
<div class="mt-2 text-sm">Informace, které budou vytištěné na Vaší konferenční jmenovku. Tyto údaje jsou nepovinné a je možné je změnit později.</div>
|
Vstupenky a příplatky
|
||||||
|
</div>
|
||||||
|
<div class="mt-2 text-sm">
|
||||||
|
Informace, které budou vytištěné na Vaší konferenční jmenovku.
|
||||||
|
Tyto údaje jsou nepovinné a je možné je změnit později.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
{#each ticketFormCountArray($orderTicketForm.count) as i}
|
{#each ticketFormCountArray($orderTicketForm.count) as i}
|
||||||
<div class="p-4 bg-utxo-gradient text-white rounded-md mb-6 shadow-md">
|
<div
|
||||||
|
class="p-4 bg-utxo-gradient text-white rounded-md mb-6 shadow-md"
|
||||||
|
>
|
||||||
<div class="">
|
<div class="">
|
||||||
<div class="uppercase font-bold">Vstupenka #{i + 1}</div>
|
<div class="uppercase font-bold">Vstupenka #{i + 1}</div>
|
||||||
<div class="md:flex gap-2">
|
<div class="md:flex gap-2">
|
||||||
<div class="mt-2 flex-1">
|
<div class="mt-2 flex-1">
|
||||||
<div class="uppercase text-sm">Jméno (Přezdívka)</div>
|
<div class="uppercase text-sm">Jméno (Přezdívka)</div>
|
||||||
<div class="mt-2"><input type="text" maxlength="25" class="border border-blue-web rounded-md p-2 w-full text-blue-web" bind:value={$orderTicketForm.tickets[i].name} placeholder="{faker.name.findName()}" /></div>
|
<div class="mt-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
maxlength="25"
|
||||||
|
class="border border-blue-web rounded-md p-2 w-full text-blue-web"
|
||||||
|
bind:value={$orderTicketForm.tickets[i].name}
|
||||||
|
placeholder={faker.name.findName()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2 flex-1">
|
<div class="mt-2 flex-1">
|
||||||
<div class="uppercase text-sm">Organizace (Firma)</div>
|
<div class="uppercase text-sm">
|
||||||
<div class="mt-2"><input type="text" maxlength="25" class="border border-blue-web rounded-md p-2 w-full text-blue-web" bind:value={$orderTicketForm.tickets[i].org} placeholder="{faker.company.companyName()}" /></div>
|
Organizace (Firma)
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
maxlength="25"
|
||||||
|
class="border border-blue-web rounded-md p-2 w-full text-blue-web"
|
||||||
|
bind:value={$orderTicketForm.tickets[i].org}
|
||||||
|
placeholder={faker.company.companyName()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<div class="uppercase text-sm">Twitter účet</div>
|
<div class="uppercase text-sm">Twitter účet</div>
|
||||||
<div class="mt-2"><input type="text" maxlength="25" class="border border-blue-web rounded-md p-2 w-full text-blue-web" bind:value={$orderTicketForm.tickets[i].twitter} placeholder="@{faker.internet.userName()}" /></div>
|
<div class="mt-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
maxlength="25"
|
||||||
|
class="border border-blue-web rounded-md p-2 w-full text-blue-web"
|
||||||
|
bind:value={$orderTicketForm.tickets[i].twitter}
|
||||||
|
placeholder="@{faker.internet.userName()}"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="uppercase text-sm font-bold mt-3">Volitelné příplatky</div>
|
</div>
|
||||||
|
<div class="uppercase text-sm font-bold mt-3">
|
||||||
|
Volitelné příplatky
|
||||||
|
</div>
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
{#each $apiStatus.config.extras as ex}
|
{#each $apiStatus.config.extras as ex}
|
||||||
<div><label class="cursor-pointer"><input type="checkbox" class="mr-0.5 cursor-pointer" bind:checked={$orderTicketForm.tickets[i].extras[ex.id]} /> <span class="font-semibold">{ex.name} ({ex.price} Kč)</span></label> - <span class="text-sm">{ex.desc}</span></div>
|
<div>
|
||||||
|
<label class="cursor-pointer"
|
||||||
|
><input
|
||||||
|
type="checkbox"
|
||||||
|
class="mr-0.5 cursor-pointer"
|
||||||
|
bind:checked={$orderTicketForm.tickets[i]
|
||||||
|
.extras[ex.id]}
|
||||||
|
/>
|
||||||
|
<span class="font-semibold"
|
||||||
|
>{ex.name} ({ex.price} Kč)</span
|
||||||
|
></label
|
||||||
|
>
|
||||||
|
- <span class="text-sm">{ex.desc}</span>
|
||||||
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -448,12 +629,30 @@
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<div class="uppercase text-sm font-bold">Dýško pro organizátory</div>
|
<div class="uppercase text-sm font-bold">
|
||||||
|
Dýško pro organizátory
|
||||||
|
</div>
|
||||||
<div class="mt-2 flex flex-wrap gap-2">
|
<div class="mt-2 flex flex-wrap gap-2">
|
||||||
{#each $apiStatus.config.tipPercentages as tp}
|
{#each $apiStatus.config.tipPercentages as tp}
|
||||||
<button class="block py-1.5 px-4 min-w-16 {$orderTicketForm.tipPercent === tp[0] && $orderTicketForm.tipCustom < 1 ? (tp[0] === 0 ? 'bg-gray-400' : 'bg-blue-web' )+' rounded-full text-white shadow-lg' : 'border border-solid border-blue-web rounded-full'}" on:click={changeTip(tp[0])}>{tp[1] || tp[0] + '%'}</button>
|
<button
|
||||||
|
class="block py-1.5 px-4 min-w-16 {$orderTicketForm.tipPercent ===
|
||||||
|
tp[0] && $orderTicketForm.tipCustom < 1
|
||||||
|
? (tp[0] === 0 ? 'bg-gray-400' : 'bg-blue-web') +
|
||||||
|
' rounded-full text-white shadow-lg'
|
||||||
|
: 'border border-solid border-blue-web rounded-full'}"
|
||||||
|
on:click={changeTip(tp[0])}>{tp[1] || tp[0] + "%"}</button
|
||||||
|
>
|
||||||
{/each}
|
{/each}
|
||||||
<div class="px-2 py-1 {$orderTicketForm.tipCustom > 0 ? 'px-5 border border-blue-web rounded-full bg-blue-web text-white' : ''}">Jiná částka: <input class="border border border-blue-web rounded-md px-2 py-1 text-blue-web w-16" bind:value={$orderTicketForm.tipCustom} /> Kč</div>
|
<div
|
||||||
|
class="px-2 py-1 {$orderTicketForm.tipCustom > 0
|
||||||
|
? 'px-5 border border-blue-web rounded-full bg-blue-web text-white'
|
||||||
|
: ''}"
|
||||||
|
>
|
||||||
|
Jiná částka: <input
|
||||||
|
class="border border border-blue-web rounded-md px-2 py-1 text-blue-web w-16"
|
||||||
|
bind:value={$orderTicketForm.tipCustom}
|
||||||
|
/> Kč
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-8">
|
<div class="mt-8">
|
||||||
|
@ -461,67 +660,113 @@
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
{#each $apiStatus.config.paymentMethods as pm}
|
{#each $apiStatus.config.paymentMethods as pm}
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<label class="cursor-pointer"><input checked={$orderTicketForm.paymentMethod === pm.id} name="paymentMethod" value="{pm.id}" type="radio" on:change={selectPaymentMethod} class="cursor-pointer" /> {pm.name}</label>
|
<label class="cursor-pointer"
|
||||||
|
><input
|
||||||
|
checked={$orderTicketForm.paymentMethod === pm.id}
|
||||||
|
name="paymentMethod"
|
||||||
|
value={pm.id}
|
||||||
|
type="radio"
|
||||||
|
on:change={selectPaymentMethod}
|
||||||
|
class="cursor-pointer"
|
||||||
|
/>
|
||||||
|
{pm.name}</label
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6 py-3 px-4 bg-white rounded-md shadow-md text-sm">
|
<div class="mt-6 py-3 px-4 bg-white rounded-md shadow-md text-sm">
|
||||||
<div class="uppercase text-sm font-bold">Shrnutí objednávky</div>
|
<div class="uppercase text-sm font-bold">
|
||||||
|
Shrnutí objednávky
|
||||||
|
</div>
|
||||||
<div class="mt-1.5">
|
<div class="mt-1.5">
|
||||||
<table cellpadding="5" class="table-auto">
|
<table cellpadding="5" class="table-auto">
|
||||||
<tr>
|
<tr>
|
||||||
<td>{$orderTicketForm.count}× UTXO.22 vstupenka ({$apiStatus.wave.price} Kč)</td>
|
<td
|
||||||
|
>{$orderTicketForm.count}× UTXO.22 vstupenka ({$apiStatus
|
||||||
|
.wave.price} Kč)</td
|
||||||
|
>
|
||||||
<td>{ticketPrice} Kč</td>
|
<td>{ticketPrice} Kč</td>
|
||||||
</tr>
|
</tr>
|
||||||
{#if extrasStats.sum > 0}
|
{#if extrasStats.sum > 0}
|
||||||
{#each extrasStats.arr as es}
|
{#each extrasStats.arr as es}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{es.count}× {$apiStatus.config.extras.find(e => e.id === es.id).shortname} ({es.price} Kč)</td>
|
<td
|
||||||
|
>{es.count}× {$apiStatus.config.extras.find(
|
||||||
|
(e) => e.id === es.id
|
||||||
|
).shortname} ({es.price} Kč)</td
|
||||||
|
>
|
||||||
<td>{es.sum} Kč</td>
|
<td>{es.sum} Kč</td>
|
||||||
</tr>
|
</tr>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
{#if tip > 0}
|
{#if tip > 0}
|
||||||
<tr>
|
<tr>
|
||||||
<td>dýško pro organizátory ({$orderTicketForm.tipPercent > 0 ? $orderTicketForm.tipPercent + '%' : $orderTicketForm.tipCustom + ' Kč'})</td>
|
<td
|
||||||
|
>dýško pro organizátory ({$orderTicketForm.tipPercent >
|
||||||
|
0
|
||||||
|
? $orderTicketForm.tipPercent + "%"
|
||||||
|
: $orderTicketForm.tipCustom + " Kč"})</td
|
||||||
|
>
|
||||||
<td>{tip} Kč</td>
|
<td>{tip} Kč</td>
|
||||||
</tr>
|
</tr>
|
||||||
{/if}
|
{/if}
|
||||||
<tr>
|
<tr>
|
||||||
<th align="right">Celkem:</th>
|
<th align="right">Celkem:</th>
|
||||||
<th class="font-bold">{totalPrice} Kč<th>
|
<th class="font-bold">{totalPrice} Kč</th><th /></tr
|
||||||
</tr>
|
>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1.5">Platební metoda: <span class="font-bold">{#if $orderTicketForm.paymentMethod === 'btcpay'}Bitcoin{:else}Platební karta{/if}</span></div>
|
<div class="mt-1.5">
|
||||||
|
Platební metoda: <span class="font-bold"
|
||||||
|
>{#if $orderTicketForm.paymentMethod === "btcpay"}Bitcoin{:else}Platební
|
||||||
|
karta{/if}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<div class="flex gap-3">
|
<div class="flex gap-3">
|
||||||
{#if !formProcessing}
|
{#if !formProcessing}
|
||||||
<div><button class="{formProcessing ? 'bg-gray-800' : 'hover:bg-utxo-gradient bg-[#E16A61]'} text-white font-semibold rounded-full shadow-md" disabled={formProcessing} on:click={submitOrderHandler}><div class="py-2 px-4">Odeslat objednávku - zaplatit {totalPrice} Kč {#if $orderTicketForm.paymentMethod === 'btcpay'}bitcoinem{:else}platební kartou{/if}</div></button></div>
|
<div>
|
||||||
|
<button
|
||||||
|
class="{formProcessing
|
||||||
|
? 'bg-gray-800'
|
||||||
|
: 'hover:bg-utxo-gradient bg-[#E16A61]'} text-white font-semibold rounded-full shadow-md"
|
||||||
|
disabled={formProcessing}
|
||||||
|
on:click={submitOrderHandler}
|
||||||
|
><div class="py-2 px-4">
|
||||||
|
Odeslat objednávku - zaplatit {totalPrice} Kč {#if $orderTicketForm.paymentMethod === "btcpay"}bitcoinem{:else}platební
|
||||||
|
kartou{/if}
|
||||||
|
</div></button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if formProcessing}
|
{#if formProcessing}
|
||||||
<div class="flex gap-3">
|
<div class="flex gap-3">
|
||||||
<div class=""><img src="/img/Spin-1s-200px.gif" class="w-10" /></div>
|
<div class="">
|
||||||
<div class="my-auto text-red-600 font-bold">Odesílám objednávku ..</div>
|
<img src="/img/Spin-1s-200px.gif" class="w-10" />
|
||||||
|
</div>
|
||||||
|
<div class="my-auto text-red-600 font-bold">
|
||||||
|
Odesílám objednávku ..
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if orderError}
|
{#if orderError}
|
||||||
<div class="py-2 px-3 mt-4 text-red-600 bg-red-200 rounded-xl shadow-md">Chyba: {orderError.title}</div>
|
<div
|
||||||
|
class="py-2 px-3 mt-4 text-red-600 bg-red-200 rounded-xl shadow-md"
|
||||||
|
>
|
||||||
|
Chyba: {orderError.title}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
<!--pre>{JSON.stringify($orderTicketForm, null, 2)}</pre>
|
<!--pre>{JSON.stringify($orderTicketForm, null, 2)}</pre>
|
||||||
<pre>{JSON.stringify(extrasStats, null, 2)}</pre -->
|
<pre>{JSON.stringify(extrasStats, null, 2)}</pre -->
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
Načítá se…
Odkázat v novém úkolu