Prettier
This commit is contained in:
rodič
b3db1527b8
revize
fe4bfb670b
|
@ -22,6 +22,8 @@
|
|||
"@sveltejs/kit": "next",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"postcss": "^8.4.12",
|
||||
"prettier": "^2.6.2",
|
||||
"prettier-plugin-svelte": "^2.7.0",
|
||||
"svelte": "^3.46.0",
|
||||
"svelte-markdown": "^0.2.2",
|
||||
"tailwindcss": "^3.0.23"
|
||||
|
@ -1571,6 +1573,31 @@
|
|||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||
"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": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
|
@ -2895,6 +2922,19 @@
|
|||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||
"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": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
"build": "svelte-kit build",
|
||||
"package": "svelte-kit package",
|
||||
"preview": "svelte-kit preview",
|
||||
"prepare": "svelte-kit sync"
|
||||
"prepare": "svelte-kit sync",
|
||||
"prettier": "prettier --write --plugin-search-dir=. ./**/*.svelte"
|
||||
|
||||
},
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^6.1.2",
|
||||
|
@ -15,6 +17,8 @@
|
|||
"@sveltejs/kit": "next",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"postcss": "^8.4.12",
|
||||
"prettier": "^2.6.2",
|
||||
"prettier-plugin-svelte": "^2.7.0",
|
||||
"svelte": "^3.46.0",
|
||||
"svelte-markdown": "^0.2.2",
|
||||
"tailwindcss": "^3.0.23"
|
||||
|
|
|
@ -1,112 +1,150 @@
|
|||
<script>
|
||||
export let speaker;
|
||||
export let col = 'speakers';
|
||||
export let size = 'normal';
|
||||
export let col = "speakers";
|
||||
export let size = "normal";
|
||||
export let customSize = null;
|
||||
|
||||
import SvelteMarkdown from 'svelte-markdown';
|
||||
import Link from '$lib/Link.svelte';
|
||||
import { page } from '$app/stores';
|
||||
import SvelteMarkdown from "svelte-markdown";
|
||||
import Link from "$lib/Link.svelte";
|
||||
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') {
|
||||
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)
|
||||
$: speakerImg = photos[0]
|
||||
$: speakerImgAlt = photos[1]
|
||||
$: photos = getPhotos(speaker);
|
||||
$: speakerImg = photos[0];
|
||||
$: speakerImgAlt = photos[1];
|
||||
|
||||
function getPhotos(sp) {
|
||||
const output = []
|
||||
const output = [];
|
||||
if (speaker.photos && speaker.photos.length > 0) {
|
||||
for (const prio of priority) {
|
||||
if (speaker.photos.includes(prio)) {
|
||||
const [ ext, format ] = prio.split(':')
|
||||
const fn = `${imagesRoot}/${col}/${speaker.id}-${ext}.${format}`
|
||||
const [ext, format] = prio.split(":");
|
||||
const fn = `${imagesRoot}/${col}/${speaker.id}-${ext}.${format}`;
|
||||
if (output[0]) {
|
||||
output.push(fn)
|
||||
break
|
||||
output.push(fn);
|
||||
break;
|
||||
}
|
||||
output.push(fn)
|
||||
output.push(fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
return output
|
||||
return output;
|
||||
}
|
||||
|
||||
if (!speakerImg) {
|
||||
speakerImg = '/img/twitter-avatar.png'
|
||||
speakerImg = "/img/twitter-avatar.png";
|
||||
}
|
||||
|
||||
function getFlagEmoji(countryCode) {
|
||||
const codePoints = countryCode
|
||||
.toUpperCase()
|
||||
.split('')
|
||||
.map(char => 127397 + char.charCodeAt());
|
||||
.split("")
|
||||
.map((char) => 127397 + char.charCodeAt());
|
||||
return String.fromCodePoint(...codePoints);
|
||||
}
|
||||
|
||||
$: country = speaker.country ? getFlagEmoji(speaker.country) : ''
|
||||
$: currentImg = speakerImg
|
||||
$: country = speaker.country ? getFlagEmoji(speaker.country) : "";
|
||||
$: currentImg = speakerImg;
|
||||
|
||||
function mouseOver() {
|
||||
if (speakerImgAlt) {
|
||||
$: currentImg = speakerImgAlt
|
||||
$: currentImg = speakerImgAlt;
|
||||
}
|
||||
}
|
||||
function mouseLeave() {
|
||||
$: currentImg = speakerImg
|
||||
$: currentImg = speakerImg;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
{#if size === 'custom'}
|
||||
{#if size === "custom"}
|
||||
<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>
|
||||
{/if}
|
||||
|
||||
{#if size === 'big'}
|
||||
{#if size === "big"}
|
||||
<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>
|
||||
{/if}
|
||||
|
||||
{#if size === 'normal'}
|
||||
{#if size === "normal"}
|
||||
<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>
|
||||
<div class="mt-4 text-sm text-blue-web uppercase font-bold"><a href="/lide?id={speaker.id}">{speaker.name}</a> {country}</div>
|
||||
<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
|
||||
>
|
||||
<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}
|
||||
<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}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if size === 'small'}
|
||||
{#if size === "small"}
|
||||
<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>
|
||||
{/if}
|
||||
|
||||
{#if size === 'semi-small'}
|
||||
{#if size === "semi-small"}
|
||||
<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>
|
||||
{/if}
|
||||
|
||||
{#if size === 'extra-small'}
|
||||
{#if size === "extra-small"}
|
||||
<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>
|
||||
{/if}
|
||||
|
||||
{#if size === 'micro'}
|
||||
{#if size === "micro"}
|
||||
<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>
|
||||
{/if}
|
||||
|
||||
|
|
|
@ -3,53 +3,70 @@
|
|||
|
||||
const e = event;
|
||||
|
||||
import Avatar from '$lib/Avatar.svelte';
|
||||
import EventTypeLabel from '$lib/EventTypeLabel.svelte';
|
||||
import Avatar from "$lib/Avatar.svelte";
|
||||
import EventTypeLabel from "$lib/EventTypeLabel.svelte";
|
||||
|
||||
import { bundle, userData } from '$lib/stores.js';
|
||||
import { bundle, userData } from "$lib/stores.js";
|
||||
|
||||
function speakersMap(arr) {
|
||||
if (!arr) return;
|
||||
return arr.map(sId => {
|
||||
return $bundle.spec.speakers.find(sp => sp.id === sId)
|
||||
})
|
||||
return arr.map((sId) => {
|
||||
return $bundle.spec.speakers.find((sp) => sp.id === sId);
|
||||
});
|
||||
}
|
||||
|
||||
function trackRender(trackId) {
|
||||
const track = $bundle.spec.tracks.find(t => t.id === trackId)
|
||||
return track.shortname || track.name
|
||||
const track = $bundle.spec.tracks.find((t) => t.id === trackId);
|
||||
return track.shortname || track.name;
|
||||
}
|
||||
|
||||
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) {
|
||||
const t = el.target.getAttribute('utxo-event-id')
|
||||
userData.update(data => {
|
||||
const fe = data.favoriteEvents
|
||||
let output = null
|
||||
const t = el.target.getAttribute("utxo-event-id");
|
||||
userData.update((data) => {
|
||||
const fe = data.favoriteEvents;
|
||||
let output = null;
|
||||
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 {
|
||||
fe.push(t)
|
||||
output = Object.assign($userData, { favoriteEvents: fe })
|
||||
fe.push(t);
|
||||
output = Object.assign($userData, { favoriteEvents: fe });
|
||||
}
|
||||
//localStorage.setItem('userData', JSON.stringify(output))
|
||||
return output
|
||||
})
|
||||
return output;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<div class="transition-all mb-4 border px-3 py-2 rounded-md shadow {$userData.favoriteEvents.includes(e.id) ? '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}></i></div>
|
||||
<div class="text-lg font-semibold"><a href="/udalosti?id={e.id}">{e.name}</a></div>
|
||||
<div
|
||||
class="transition-all mb-4 border px-3 py-2 rounded-md shadow {$userData.favoriteEvents.includes(
|
||||
e.id
|
||||
)
|
||||
? '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}
|
||||
<div class="mt-1 mb-2 flex flex-wrap gap-2">
|
||||
{#each speakersMap(e.speakers) as s}
|
||||
<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>
|
||||
{/each}
|
||||
|
@ -65,13 +82,18 @@
|
|||
<div class="flex flex-wrap gap-2" cellpadding="5">
|
||||
{#each getParents(e) as pe}
|
||||
<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">
|
||||
{#if pe.speakers.length === 0}
|
||||
<div>TBA</div>
|
||||
{:else}
|
||||
{#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}
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -3,19 +3,23 @@
|
|||
export let size = null;
|
||||
|
||||
const config = {
|
||||
panel: { title: 'Panelová debata', style: 'bg-custom-red text-white' },
|
||||
talk: { title: 'Přednáška', style: 'bg-custom-green text-white' },
|
||||
workshop: { title: 'Workshop', style: 'bg-custom-blue text-white' },
|
||||
other: { title: 'Ostatní', style: 'bg-custom-yellow' },
|
||||
lightning: { title: 'Lightning talk', style: 'bg-pink-400' },
|
||||
}
|
||||
panel: { title: "Panelová debata", style: "bg-custom-red text-white" },
|
||||
talk: { title: "Přednáška", style: "bg-custom-green text-white" },
|
||||
workshop: { title: "Workshop", style: "bg-custom-blue text-white" },
|
||||
other: { title: "Ostatní", style: "bg-custom-yellow" },
|
||||
lightning: { title: "Lightning talk", style: "bg-pink-400" },
|
||||
};
|
||||
|
||||
const current = config[event.type];
|
||||
|
||||
</script>
|
||||
|
||||
<div class="flex {size === 'big' ? 'h-6 text-sm' : 'h-5 text-xs'}">
|
||||
<div class="w-1 rounded-l-sm {current.style}"></div>
|
||||
<div class="{ size === 'big' ? 'px-2 py-0.5' : 'px-1.5 py-0.5' } rounded-r-sm bg-gray-100 uppercase">{current.title}</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>
|
||||
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
<script>
|
||||
import { bundle } from '$lib/stores';
|
||||
import SocialButtons from '$lib/SocialButtons.svelte';
|
||||
import { bundle } from "$lib/stores";
|
||||
import SocialButtons from "$lib/SocialButtons.svelte";
|
||||
</script>
|
||||
|
||||
{#if $bundle}
|
||||
<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>
|
||||
<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 class="mt-4 font-semibold">
|
||||
4.-5. červen 2022 @ Gabriel Loci, Praha
|
||||
|
@ -17,21 +21,42 @@
|
|||
Otevřená komunitní kryptoměnová konference
|
||||
</div>
|
||||
<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 class="sm:mt-0 mt-6 sm:w-1/3 mr-2">
|
||||
<SocialButtons size="normal" />
|
||||
</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">
|
||||
<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>
|
||||
<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://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>
|
||||
<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://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>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<script>
|
||||
export let href = ''
|
||||
export let title = undefined
|
||||
export let href = "";
|
||||
export let title = undefined;
|
||||
</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>
|
||||
export let size = 'small';
|
||||
export let size = "small";
|
||||
|
||||
import { bundle } from '$lib/stores';
|
||||
import { page } from '$app/stores';
|
||||
import { bundle } from "$lib/stores";
|
||||
import { page } from "$app/stores";
|
||||
|
||||
const socials = [
|
||||
{ link: 'twitter', ico: 'fa-brands fa-twitter', name: 'Twitter' },
|
||||
{ link: 'instagram', ico: 'fab fa-instagram', name: 'Instagram' },
|
||||
{ link: 'fbevent', ico: 'fab fa-facebook', name: 'Facebook' },
|
||||
{ link: 'substack', ico: 'fa-solid fa-envelope', name: 'Newsletter' },
|
||||
{ link: 'discord', ico: 'fab fa-discord', name: 'Discord' },
|
||||
{ link: 'telegram', ico: 'fab fa-telegram', name: 'Telegram' },
|
||||
]
|
||||
{ link: "twitter", ico: "fa-brands fa-twitter", name: "Twitter" },
|
||||
{ link: "instagram", ico: "fab fa-instagram", name: "Instagram" },
|
||||
{ link: "fbevent", ico: "fab fa-facebook", name: "Facebook" },
|
||||
{ link: "substack", ico: "fa-solid fa-envelope", name: "Newsletter" },
|
||||
{ link: "discord", ico: "fab fa-discord", name: "Discord" },
|
||||
{ link: "telegram", ico: "fab fa-telegram", name: "Telegram" },
|
||||
];
|
||||
</script>
|
||||
|
||||
{#if $bundle}
|
||||
{#if size === 'small'}
|
||||
{#if size === "small"}
|
||||
<div class="flex block space-x-2 m-auto w-full justify-end">
|
||||
{#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">
|
||||
<i class="{soc.ico}" />
|
||||
<a
|
||||
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>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{#if size === 'normal'}
|
||||
{#if size === "normal"}
|
||||
<div class="w-auto">
|
||||
<div class="sm:flex flex-wrap gap-3 justify-end">
|
||||
{#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}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,31 +1,61 @@
|
|||
<script>
|
||||
import { page } from '$app/stores';
|
||||
import { bundle, userData, userDataLocal } from '$lib/stores';
|
||||
import SocialButtons from '$lib/SocialButtons.svelte';
|
||||
import { page } from "$app/stores";
|
||||
import { bundle, userData, userDataLocal } from "$lib/stores";
|
||||
import SocialButtons from "$lib/SocialButtons.svelte";
|
||||
|
||||
function logoClick() {
|
||||
userData.update(ud => {
|
||||
ud.hpTrack = 'top'
|
||||
return ud
|
||||
})
|
||||
userData.update((ud) => {
|
||||
ud.hpTrack = "top";
|
||||
return ud;
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<header class="relative" style="background-color: #32375C;">
|
||||
<!-- <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="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 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
|
||||
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 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 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>
|
||||
<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
|
||||
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 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 />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,40 +1,37 @@
|
|||
<script>
|
||||
import Header from '$lib/header/Header.svelte';
|
||||
import Footer from '$lib/Footer.svelte';
|
||||
import '../app.css';
|
||||
import api from '$lib/api.js';
|
||||
import { page } from '$app/stores';
|
||||
import { userData, userDataLocal, apiStatus } from '$lib/stores';
|
||||
import { loadOrders, loadApiStatus } from '$lib/orders';
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import Header from "$lib/header/Header.svelte";
|
||||
import Footer from "$lib/Footer.svelte";
|
||||
import "../app.css";
|
||||
import api from "$lib/api.js";
|
||||
import { page } from "$app/stores";
|
||||
import { userData, userDataLocal, apiStatus } from "$lib/stores";
|
||||
import { loadOrders, loadApiStatus } from "$lib/orders";
|
||||
import { onMount, onDestroy } from "svelte";
|
||||
|
||||
let bundle = null
|
||||
let uds = null
|
||||
let bundle = null;
|
||||
let uds = null;
|
||||
|
||||
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) {
|
||||
userData.set(JSON.parse(userDataLS))
|
||||
userData.set(JSON.parse(userDataLS));
|
||||
}
|
||||
|
||||
uds = userData.subscribe(ud => {
|
||||
localStorage.setItem('userData', JSON.stringify(ud))
|
||||
})
|
||||
uds = userData.subscribe((ud) => {
|
||||
localStorage.setItem("userData", JSON.stringify(ud));
|
||||
});
|
||||
|
||||
await loadApiStatus()
|
||||
await loadOrders($userData)
|
||||
})
|
||||
await loadApiStatus();
|
||||
await loadOrders($userData);
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
//userData.unsubscribe(uds)
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
|
||||
// load orders
|
||||
|
||||
</script>
|
||||
|
||||
{#if bundle}
|
||||
|
|
|
@ -7,11 +7,41 @@
|
|||
|
||||
<section class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl text-blue-web">
|
||||
<div class="">
|
||||
<div class="text-3xl lg:text-4xl text-center">🎉 Gratulujeme k nákupu vstupenek!</div>
|
||||
<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>
|
||||
<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"></i></div>
|
||||
<div class="text-3xl lg:text-4xl text-center">
|
||||
🎉 Gratulujeme k nákupu vstupenek!
|
||||
</div>
|
||||
<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>
|
||||
<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>
|
||||
</section>
|
||||
|
|
|
@ -3,59 +3,92 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
import { bundle, userData } from '$lib/stores.js';
|
||||
import Avatar from '$lib/Avatar.svelte';
|
||||
import SvelteMarkdown from 'svelte-markdown';
|
||||
import Link from '$lib/Link.svelte';
|
||||
const renderers = { link: Link }
|
||||
import { bundle, userData } from "$lib/stores.js";
|
||||
import Avatar from "$lib/Avatar.svelte";
|
||||
import SvelteMarkdown from "svelte-markdown";
|
||||
import Link from "$lib/Link.svelte";
|
||||
const renderers = { link: Link };
|
||||
|
||||
let onlyLead = true
|
||||
let onlyLeadPreview = false
|
||||
let onlyLead = true;
|
||||
let onlyLeadPreview = false;
|
||||
|
||||
$: currentBundle = $bundle;
|
||||
$: leadSpeakersCount = currentBundle ? 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
|
||||
$: leadSpeakersCount = currentBundle
|
||||
? 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) {
|
||||
return function () {
|
||||
userData.update(ud => { ud.hpTrack = tId; return ud; })
|
||||
onlyLead = !tId
|
||||
}
|
||||
userData.update((ud) => {
|
||||
ud.hpTrack = tId;
|
||||
return ud;
|
||||
});
|
||||
onlyLead = !tId;
|
||||
};
|
||||
}
|
||||
|
||||
function handleShowFull() {
|
||||
userData.update(ud => { ud.hpTrack = null; return ud })
|
||||
userData.update((ud) => {
|
||||
ud.hpTrack = null;
|
||||
return ud;
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<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>
|
||||
|
||||
<section class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl">
|
||||
{#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}
|
||||
<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}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap gap-6 mt-6 sm:mt-14 justify-center">
|
||||
{#each $bundle.spec.speakers as speaker}
|
||||
{#if ($userData.hpTrack === 'top' && speaker.lead === true) || $userData.hpTrack !== 'top'}
|
||||
{#if (!$userData.hpTrack || speaker.tracks.includes($userData.hpTrack)) || $userData.hpTrack === 'top'}
|
||||
<Avatar speaker={speaker} />
|
||||
{#if ($userData.hpTrack === "top" && speaker.lead === true) || $userData.hpTrack !== "top"}
|
||||
{#if !$userData.hpTrack || speaker.tracks.includes($userData.hpTrack) || $userData.hpTrack === "top"}
|
||||
<Avatar {speaker} />
|
||||
{/if}
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{#if $userData.hpTrack === 'top'}
|
||||
{#if $userData.hpTrack === "top"}
|
||||
<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">
|
||||
{#each $bundle.spec.speakers.filter(s => !s.lead).sort(() => .5 - Math.random()).slice(0,27) as speaker}
|
||||
<Avatar speaker={speaker} size="small" />
|
||||
{#each $bundle.spec.speakers
|
||||
.filter((s) => !s.lead)
|
||||
.sort(() => 0.5 - Math.random())
|
||||
.slice(0, 27) as speaker}
|
||||
<Avatar {speaker} size="small" />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -67,24 +100,57 @@
|
|||
<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="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="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"><img src="/photos/knihovna.jpeg" class="rounded-lg shadow-lg" alt="Gabriel Loci - Knihovna" /></div>
|
||||
<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">
|
||||
<img
|
||||
src="/photos/knihovna.jpeg"
|
||||
class="rounded-lg shadow-lg"
|
||||
alt="Gabriel Loci - Knihovna"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-white md:w-1/2 md:pt-0 pt-6">
|
||||
<div class="uppercase">Místo</div>
|
||||
<div class="uppercase mt-3 text-4xl font-bold">Gabriel Loci</div>
|
||||
<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 class="mt-4">
|
||||
Benediktinky. Kulturní památka. Česká Pošta. Poštovní muzeum.
|
||||
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.
|
||||
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ů.
|
||||
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 👌😀
|
||||
Benediktinky. Kulturní památka. Česká Pošta. Poštovní muzeum. 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. 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ů. 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>
|
||||
|
@ -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="mt-6">Sponzoři</div>
|
||||
<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">
|
||||
<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>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="mt-10">Komunity</div>
|
||||
<div class="mt-6 flex flex-wrap gap-6 justify-left">
|
||||
{#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>
|
||||
{#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>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="mt-10">Mediální partneři</div>
|
||||
<div class="mt-6 flex flex-wrap gap-4 justify-left">
|
||||
{#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>
|
||||
{#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>
|
||||
{/each}
|
||||
</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>
|
||||
<div class="md:columns-2 columns-1 mt-8 h-auto">
|
||||
{#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>
|
||||
<SvelteMarkdown source={item.answer} renderers={renderers} />
|
||||
<SvelteMarkdown source={item.answer} {renderers} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
|
|
@ -3,47 +3,49 @@
|
|||
</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';
|
||||
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 }
|
||||
|
||||
$: 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)) : []
|
||||
$: 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) {
|
||||
const searchParams = new URLSearchParams(search)
|
||||
const cid = searchParams.get('id')
|
||||
if (!$bundle.spec.speakers.find(s => s.id === cid)) {
|
||||
goto('/')
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const cid = searchParams.get("id");
|
||||
if (!$bundle.spec.speakers.find((s) => s.id === cid)) {
|
||||
goto("/");
|
||||
}
|
||||
return cid
|
||||
return cid;
|
||||
}
|
||||
|
||||
function trackRender(trackId) {
|
||||
const track = $bundle.spec.tracks.find(t => t.id === trackId)
|
||||
return track.shortname || track.name
|
||||
const track = $bundle.spec.tracks.find((t) => t.id === trackId);
|
||||
return track.shortname || track.name;
|
||||
}
|
||||
|
||||
function getFlagEmoji(countryCode) {
|
||||
const codePoints = countryCode
|
||||
.toUpperCase()
|
||||
.split('')
|
||||
.map(char => 127397 + char.charCodeAt());
|
||||
.split("")
|
||||
.map((char) => 127397 + char.charCodeAt());
|
||||
return String.fromCodePoint(...codePoints);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<h1 class="text-2xl font-bold">{s.name} {getFlagEmoji(s.country)}</h1>
|
||||
{#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 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 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}
|
||||
<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}
|
||||
<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 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 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}
|
||||
</div>
|
||||
</div>
|
||||
{#if s.desc}
|
||||
<div class="mt-6">
|
||||
<SvelteMarkdown source={s.desc} renderers={renderers} />
|
||||
<SvelteMarkdown source={s.desc} {renderers} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="mt-6">
|
||||
|
|
|
@ -3,22 +3,23 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
import Event from '$lib/Event.svelte';
|
||||
import { bundle, userData } from '$lib/stores.js';
|
||||
|
||||
import Event from "$lib/Event.svelte";
|
||||
import { bundle, userData } from "$lib/stores.js";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Program | UTXO.22</title>
|
||||
</svelte:head>
|
||||
|
||||
|
||||
<section class="relative mx-auto py-6 sm:py-10 px-6 max-w-6xl text-blue-web">
|
||||
<h1 class="uppercase text-2xl font-bold">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">
|
||||
{#each $bundle.spec.events.filter(e => !e.parent) as e}
|
||||
{#each $bundle.spec.events.filter((e) => !e.parent) as e}
|
||||
<Event event={e} />
|
||||
{/each}
|
||||
</div>
|
||||
|
|
|
@ -3,45 +3,46 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { onMount } from 'svelte';
|
||||
import { bundle, userData } from '$lib/stores.js';
|
||||
import EventTypeLabel from '$lib/EventTypeLabel.svelte';
|
||||
import Avatar from '$lib/Avatar.svelte';
|
||||
import SvelteMarkdown from 'svelte-markdown';
|
||||
import Link from '$lib/Link.svelte';
|
||||
import { page } from "$app/stores";
|
||||
import { goto } from "$app/navigation";
|
||||
import { onMount } from "svelte";
|
||||
import { bundle, userData } from "$lib/stores.js";
|
||||
import EventTypeLabel from "$lib/EventTypeLabel.svelte";
|
||||
import Avatar from "$lib/Avatar.svelte";
|
||||
import SvelteMarkdown from "svelte-markdown";
|
||||
import Link from "$lib/Link.svelte";
|
||||
|
||||
const renderers = { link: Link }
|
||||
const renderers = { link: Link };
|
||||
|
||||
$: id = getId($page.url.search)
|
||||
$: e = $bundle ? $bundle.spec.events.find(ev => ev.id === id) : null
|
||||
$: id = getId($page.url.search);
|
||||
$: e = $bundle ? $bundle.spec.events.find((ev) => ev.id === id) : null;
|
||||
|
||||
function getId(search) {
|
||||
const searchParams = new URLSearchParams(search)
|
||||
const cid = searchParams.get('id')
|
||||
if (!$bundle.spec.events.find(s => s.id === cid)) {
|
||||
goto('/')
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const cid = searchParams.get("id");
|
||||
if (!$bundle.spec.events.find((s) => s.id === cid)) {
|
||||
goto("/");
|
||||
}
|
||||
return cid
|
||||
return cid;
|
||||
}
|
||||
|
||||
function speakersMap(arr) {
|
||||
if (!arr) return;
|
||||
return arr.map(sId => {
|
||||
return $bundle.spec.speakers.find(sp => sp.id === sId)
|
||||
})
|
||||
return arr.map((sId) => {
|
||||
return $bundle.spec.speakers.find((sp) => sp.id === sId);
|
||||
});
|
||||
}
|
||||
|
||||
function trackRender(trackId) {
|
||||
const track = $bundle.spec.tracks.find(t => t.id === trackId)
|
||||
return track.shortname || track.name
|
||||
const track = $bundle.spec.tracks.find((t) => t.id === trackId);
|
||||
return track.shortname || track.name;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<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>
|
||||
|
||||
<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">
|
||||
{#each speakersMap(e.speakers) as s}
|
||||
<div class="flex gap-2">
|
||||
<Avatar speaker={s} size='semi-small' />
|
||||
<div class="m-auto"><a href="/lide?id={s.id}" class="text-xl">{s.name}</a></div>
|
||||
<Avatar speaker={s} size="semi-small" />
|
||||
<div class="m-auto">
|
||||
<a href="/lide?id={s.id}" class="text-xl">{s.name}</a>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="mt-8">
|
||||
{#if e.description}
|
||||
<SvelteMarkdown source={e.description} renderers={renderers}/>
|
||||
<SvelteMarkdown source={e.description} {renderers} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
@ -3,268 +3,299 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { orderTicketForm, apiStatus, userData, userDataLocal } from '$lib/stores';
|
||||
import { onMount, onDestroy } from "svelte";
|
||||
import { faker } from "@faker-js/faker";
|
||||
import {
|
||||
orderTicketForm,
|
||||
apiStatus,
|
||||
userData,
|
||||
userDataLocal,
|
||||
} from "$lib/stores";
|
||||
//import btcPay from 'https://btcpay.utxo.cz/modal/btcpay.js';
|
||||
import api from '$lib/api.js';
|
||||
import makeBlockie from 'ethereum-blockies-base64';
|
||||
import { format, formatDistanceToNow } from 'date-fns';
|
||||
import { cs } from 'date-fns/locale/index.js'
|
||||
import api from "$lib/api.js";
|
||||
import makeBlockie from "ethereum-blockies-base64";
|
||||
import { format, formatDistanceToNow } from "date-fns";
|
||||
import { cs } from "date-fns/locale/index.js";
|
||||
|
||||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { loadOrders, loadApiStatus } from '$lib/orders';
|
||||
import { page } from "$app/stores";
|
||||
import { goto } from "$app/navigation";
|
||||
import { loadOrders, loadApiStatus } from "$lib/orders";
|
||||
|
||||
const orderTicketFormLS = localStorage.getItem('orderTicketForm')
|
||||
let parsed = JSON.parse(orderTicketFormLS)
|
||||
const orderTicketFormLS = localStorage.getItem("orderTicketForm");
|
||||
let parsed = JSON.parse(orderTicketFormLS);
|
||||
if (parsed && parsed.__v === $orderTicketForm.__v) {
|
||||
orderTicketForm.set(parsed)
|
||||
orderTicketForm.set(parsed);
|
||||
}
|
||||
|
||||
let forceShow = false
|
||||
let loading = true
|
||||
let formProcessing = false
|
||||
$: showOrder = !(($userDataLocal.orders && $userDataLocal.orders.length > 0) || ($userDataLocal.tickets && $userDataLocal.tickets.length > 0))
|
||||
$: orders = $userDataLocal.orders
|
||||
$: tickets = $userDataLocal.tickets
|
||||
let forceShow = false;
|
||||
let loading = true;
|
||||
let formProcessing = false;
|
||||
$: showOrder = !(
|
||||
($userDataLocal.orders && $userDataLocal.orders.length > 0) ||
|
||||
($userDataLocal.tickets && $userDataLocal.tickets.length > 0)
|
||||
);
|
||||
$: orders = $userDataLocal.orders;
|
||||
$: tickets = $userDataLocal.tickets;
|
||||
|
||||
|
||||
let periodic15 = null
|
||||
let periodic60 = null
|
||||
let periodic15 = null;
|
||||
let periodic60 = null;
|
||||
|
||||
onMount(async () => {
|
||||
|
||||
const sp = $page.url.searchParams
|
||||
if (sp.get('done')) {
|
||||
goto('/gratulujeme');
|
||||
const sp = $page.url.searchParams;
|
||||
if (sp.get("done")) {
|
||||
goto("/gratulujeme");
|
||||
}
|
||||
if (sp.get('id') && sp.get('secret')) {
|
||||
userData.update(ud => {
|
||||
if (sp.get("id") && sp.get("secret")) {
|
||||
userData.update((ud) => {
|
||||
if (!ud.tickets) ud.tickets = [];
|
||||
ud.tickets.push([ sp.get('id'), sp.get('secret') ].join(':'))
|
||||
return ud
|
||||
})
|
||||
await loadOrders($userData)
|
||||
goto('/vstupenky');
|
||||
ud.tickets.push([sp.get("id"), sp.get("secret")].join(":"));
|
||||
return ud;
|
||||
});
|
||||
await loadOrders($userData);
|
||||
goto("/vstupenky");
|
||||
}
|
||||
loading = false
|
||||
loading = false;
|
||||
|
||||
periodic15 = setInterval(() => {
|
||||
loadApiStatus()
|
||||
}, 15 * 1000)
|
||||
loadApiStatus();
|
||||
}, 15 * 1000);
|
||||
|
||||
periodic60 = setInterval(() => {
|
||||
loadOrders($userData)
|
||||
}, 60 * 1000)
|
||||
})
|
||||
loadOrders($userData);
|
||||
}, 60 * 1000);
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
clearInterval(periodic15)
|
||||
clearInterval(periodic60)
|
||||
})
|
||||
clearInterval(periodic15);
|
||||
clearInterval(periodic60);
|
||||
});
|
||||
|
||||
faker.locale = 'cz';
|
||||
let orderError = null
|
||||
faker.locale = "cz";
|
||||
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) {
|
||||
orderTicketForm.update(f => {
|
||||
f.paymentMethod = el.target.value
|
||||
return f
|
||||
})
|
||||
orderTicketForm.update((f) => {
|
||||
f.paymentMethod = el.target.value;
|
||||
return f;
|
||||
});
|
||||
}
|
||||
|
||||
function ticketFormCountArray(count) {
|
||||
return [...Array(count).keys()].map(i => i)
|
||||
return [...Array(count).keys()].map((i) => i);
|
||||
}
|
||||
|
||||
function processOrderError(error) {
|
||||
if (typeof error === 'string') {
|
||||
return { title: error }
|
||||
if (typeof error === "string") {
|
||||
return { title: error };
|
||||
}
|
||||
const out = { title: error.title }
|
||||
const out = { title: error.title };
|
||||
if (error.formErrors && error.formErrors.length > 0) {
|
||||
let suberrs = []
|
||||
if (error.formErrors.find(fe => fe.instancePath === '/email')) {
|
||||
suberrs.push(`Neplatný email`)
|
||||
let suberrs = [];
|
||||
if (error.formErrors.find((fe) => fe.instancePath === "/email")) {
|
||||
suberrs.push(`Neplatný email`);
|
||||
}
|
||||
|
||||
let ticket = null
|
||||
if (error.formErrors.find(fe => ticket = fe.instancePath.match(/\/tickets\/(\d+)\/twitter/))) {
|
||||
suberrs.push(`Neplatný Twitter účet (Vstupenka #${Number(ticket[1])+1}).`)
|
||||
let ticket = null;
|
||||
if (
|
||||
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.debug = error.formErrors
|
||||
|
||||
out.title =
|
||||
"Nesprávně vyplněný formulář: " +
|
||||
(suberrs.length > 0 ? suberrs.join(",") : "neznámá chyba");
|
||||
out.debug = error.formErrors;
|
||||
}
|
||||
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)
|
||||
return out
|
||||
console.log(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
async function submitOrderHandler() {
|
||||
// order process
|
||||
formProcessing = true
|
||||
formProcessing = true;
|
||||
|
||||
// clean previous errors
|
||||
$: orderError = null
|
||||
$: orderError = null;
|
||||
|
||||
const cloned = Object.assign({}, $orderTicketForm)
|
||||
cloned.tipCustom = Number(cloned.tipCustom)
|
||||
cloned.totalPrice = totalPrice
|
||||
const resp = await api.submitOrder(cloned)
|
||||
const cloned = Object.assign({}, $orderTicketForm);
|
||||
cloned.tipCustom = Number(cloned.tipCustom);
|
||||
cloned.totalPrice = totalPrice;
|
||||
const resp = await api.submitOrder(cloned);
|
||||
|
||||
if (resp.error) {
|
||||
$: orderError = processOrderError(resp.error)
|
||||
formProcessing = false
|
||||
$: orderError = processOrderError(resp.error);
|
||||
formProcessing = false;
|
||||
return null;
|
||||
}
|
||||
if (!resp.ok || !resp.payment.url) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
// reset tickets in form
|
||||
orderTicketForm.update(of => {
|
||||
of.count = 1
|
||||
of.tickets = []
|
||||
return of
|
||||
})
|
||||
orderTicketForm.update((of) => {
|
||||
of.count = 1;
|
||||
of.tickets = [];
|
||||
return of;
|
||||
});
|
||||
|
||||
// add order to user data
|
||||
userData.update(ud => {
|
||||
userData.update((ud) => {
|
||||
if (!ud.orders) {
|
||||
ud.orders = []
|
||||
ud.orders = [];
|
||||
}
|
||||
ud.orders.push(resp.orderId)
|
||||
return ud
|
||||
})
|
||||
ud.orders.push(resp.orderId);
|
||||
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) {
|
||||
ticketsNum = f.count
|
||||
orderTicketForm.update(cf => {
|
||||
f.tickets = f.tickets.slice(0, f.count)
|
||||
ticketsNum = f.count;
|
||||
orderTicketForm.update((cf) => {
|
||||
f.tickets = f.tickets.slice(0, f.count);
|
||||
for (let i = 0; i < f.count; i++) {
|
||||
console.log(i)
|
||||
console.log(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) {
|
||||
return () => {
|
||||
orderTicketForm.update(of => {
|
||||
of.tipPercent = perc
|
||||
of.tipCustom = ''
|
||||
return of
|
||||
})
|
||||
}
|
||||
orderTicketForm.update((of) => {
|
||||
of.tipPercent = perc;
|
||||
of.tipCustom = "";
|
||||
return of;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
orderTicketForm.subscribe(of => {
|
||||
const val = Number(of.tipCustom)
|
||||
orderTicketForm.subscribe((of) => {
|
||||
const val = Number(of.tipCustom);
|
||||
if (val === NaN || !val || val < 1 || !String(val).match(/^\d+$/)) {
|
||||
of.tipCustom = ''
|
||||
}
|
||||
else if (val && val > 0 && of.tipPercent > 0) {
|
||||
of.tipPercent = 0
|
||||
of.tipCustom = "";
|
||||
} else if (val && val > 0 && of.tipPercent > 0) {
|
||||
of.tipPercent = 0;
|
||||
}
|
||||
if (orderError) {
|
||||
orderError = false
|
||||
orderError = false;
|
||||
}
|
||||
return of
|
||||
})
|
||||
return of;
|
||||
});
|
||||
|
||||
function roundPrice(num) {
|
||||
return Math.round(num * 100) / 100
|
||||
return Math.round(num * 100) / 100;
|
||||
}
|
||||
|
||||
function extrasStatsRender(form) {
|
||||
let obj = {}
|
||||
$apiStatus.config.extras.forEach(ex => {
|
||||
obj[ex.id] = { count: 0, sum: 0, price: ex.price }
|
||||
form.tickets.forEach(t => {
|
||||
let obj = {};
|
||||
$apiStatus.config.extras.forEach((ex) => {
|
||||
obj[ex.id] = { count: 0, sum: 0, price: ex.price };
|
||||
form.tickets.forEach((t) => {
|
||||
if (t.extras[ex.id]) {
|
||||
obj[ex.id].count++
|
||||
obj[ex.id].sum = obj[ex.id].count * ex.price
|
||||
obj[ex.id].count++;
|
||||
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 {
|
||||
sum: arr.reduce((p, c) => p + c.sum, 0),
|
||||
arr
|
||||
}
|
||||
arr,
|
||||
};
|
||||
}
|
||||
|
||||
$: extrasStats = $apiStatus ? extrasStatsRender($orderTicketForm) : {}
|
||||
$: ticketPrice = $apiStatus && $apiStatus.wave ? $orderTicketForm.count * $apiStatus.wave.price : 0
|
||||
$: totalBeforeTip = ticketPrice + extrasStats.sum
|
||||
$: tip = roundPrice($orderTicketForm.tipPercent > 0 ? $orderTicketForm.tipPercent * (totalBeforeTip/100) : Number($orderTicketForm.tipCustom))
|
||||
$: totalPrice = totalBeforeTip + tip
|
||||
$: extrasStats = $apiStatus ? extrasStatsRender($orderTicketForm) : {};
|
||||
$: ticketPrice =
|
||||
$apiStatus && $apiStatus.wave
|
||||
? $orderTicketForm.count * $apiStatus.wave.price
|
||||
: 0;
|
||||
$: totalBeforeTip = ticketPrice + extrasStats.sum;
|
||||
$: tip = roundPrice(
|
||||
$orderTicketForm.tipPercent > 0
|
||||
? $orderTicketForm.tipPercent * (totalBeforeTip / 100)
|
||||
: Number($orderTicketForm.tipCustom)
|
||||
);
|
||||
$: totalPrice = totalBeforeTip + tip;
|
||||
|
||||
const orderStatuses = {
|
||||
new: {
|
||||
name: 'Čeká na platbu',
|
||||
icon: 'fa-solid fa-clock',
|
||||
color: 'text-yellow-600',
|
||||
name: "Čeká na platbu",
|
||||
icon: "fa-solid fa-clock",
|
||||
color: "text-yellow-600",
|
||||
text: (o) => {
|
||||
return 'Tato objednávka čeká na platbu'
|
||||
return "Tato objednávka čeká na platbu";
|
||||
},
|
||||
},
|
||||
done: {
|
||||
name: 'Zaplacená',
|
||||
icon: 'fa-solid fa-check',
|
||||
color: 'text-green-600'
|
||||
name: "Zaplacená",
|
||||
icon: "fa-solid fa-check",
|
||||
color: "text-green-600",
|
||||
},
|
||||
cancelled: {
|
||||
name: 'Zrušená',
|
||||
icon: 'fa-solid fa-ban',
|
||||
color: 'text-gray-600'
|
||||
name: "Zrušená",
|
||||
icon: "fa-solid fa-ban",
|
||||
color: "text-gray-600",
|
||||
},
|
||||
expired: {
|
||||
name: 'Expirovaná',
|
||||
icon: 'fa-solid fa-clock',
|
||||
color: 'text-gray-600'
|
||||
}
|
||||
}
|
||||
name: "Expirovaná",
|
||||
icon: "fa-solid fa-clock",
|
||||
color: "text-gray-600",
|
||||
},
|
||||
};
|
||||
|
||||
async function orderActionHandler(id, action) {
|
||||
const resp = await api.apiCall('updateOrder', { method: 'POST' }, { id, action })
|
||||
loadOrders($userData)
|
||||
loadApiStatus()
|
||||
const resp = await api.apiCall(
|
||||
"updateOrder",
|
||||
{ method: "POST" },
|
||||
{ id, action }
|
||||
);
|
||||
loadOrders($userData);
|
||||
loadApiStatus();
|
||||
}
|
||||
|
||||
function removeOrder(id) {
|
||||
userData.update(ud => {
|
||||
console.log('change', ud.orders, id)
|
||||
let index = ud.orders.indexOf(id)
|
||||
userData.update((ud) => {
|
||||
console.log("change", ud.orders, id);
|
||||
let index = ud.orders.indexOf(id);
|
||||
if (index >= 0) {
|
||||
if (ud.orders.length === 1) {
|
||||
ud.orders = []
|
||||
ud.orders = [];
|
||||
} else {
|
||||
ud.orders.splice(index, 1)
|
||||
ud.orders.splice(index, 1);
|
||||
}
|
||||
}
|
||||
return ud
|
||||
})
|
||||
loadOrders($userData)
|
||||
return ud;
|
||||
});
|
||||
loadOrders($userData);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -281,21 +312,37 @@
|
|||
<div class="mt-4 flex flex-wrap gap-3">
|
||||
{#each tickets as ticket}
|
||||
<div class="w-full sm:w-80">
|
||||
<div class="h-2 bg-blue-web rounded-t-md shadow-md"></div>
|
||||
<div class="border-l border-b border-r p-4 rounded-b-md shadow-md border-blue-web">
|
||||
<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="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="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 class="mt-1.5">Běžná vstupenka</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if ticket.data}
|
||||
<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.twitter}<a href="https://twitter.com/{ticket.data.twitter}" target="_blank"><i class="fa-brands fa-twitter"></i></a>{/if}
|
||||
{#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.twitter}<a
|
||||
href="https://twitter.com/{ticket.data.twitter}"
|
||||
target="_blank"><i class="fa-brands fa-twitter" /></a
|
||||
>{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -313,32 +360,71 @@
|
|||
<div class="mt-4">
|
||||
{#each orders as order}
|
||||
<div class="mb-2 px-3 py-2 border rounded-lg">
|
||||
{#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>
|
||||
{#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" /></a
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex flex-wrap gap-3 text-sm">
|
||||
<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}
|
||||
<i class="{orderStatuses[order.status].icon} mr-0.5"></i>
|
||||
<i class="{orderStatuses[order.status].icon} mr-0.5" />
|
||||
{/if}
|
||||
{orderStatuses[order.status].name}
|
||||
{#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 })})
|
||||
{#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 }
|
||||
)})
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<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>Čá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>
|
||||
Vytvořeno: <span class="font-bold"
|
||||
>{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>
|
||||
{#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}
|
||||
<div class="flex gap-3">
|
||||
{#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}
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -352,45 +438,79 @@
|
|||
<h1 class="uppercase text-2xl font-bold">Nákup vstupenek</h1>
|
||||
<div class="mt-4 mb-8">
|
||||
<div class="flex w-full uppercase text-sm mb-2">
|
||||
<div class="flex-1">{$apiStatus.wave.name} ({$apiStatus.wave.price} Kč)</div>
|
||||
<div class="justify-end">Zbývá {$apiStatus.wave.live.left} / {$apiStatus.wave.count}</div>
|
||||
<div class="flex-1">
|
||||
{$apiStatus.wave.name} ({$apiStatus.wave.price} Kč)
|
||||
</div>
|
||||
<div class="justify-end">
|
||||
Zbývá {$apiStatus.wave.live.left} / {$apiStatus.wave.count}
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
{#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>
|
||||
{:else}
|
||||
{#if !showOrder && !forceShow}
|
||||
<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 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>
|
||||
{:else}
|
||||
{#if !$apiStatus.wave}
|
||||
{:else if !showOrder && !forceShow}
|
||||
<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>
|
||||
{: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="mb-4">
|
||||
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/>
|
||||
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 })
|
||||
Datum konání: <span class="font-bold">4. - 5. červen 2022</span>
|
||||
(sobota - neděle)<br />
|
||||
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 class="md:flex gap-3">
|
||||
<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="mb-2">• přístup na všechny přednášky, workshopy a další události 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 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">
|
||||
• 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 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="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>
|
||||
|
@ -398,49 +518,110 @@
|
|||
<div class="p-2">
|
||||
<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"><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 class="mt-2 text-sm">
|
||||
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 class="mt-6">
|
||||
<div class="uppercase text-sm font-bold">Počet vstupenek</div>
|
||||
<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}
|
||||
<option value={i}>{i}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<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 class="mt-6">
|
||||
<div class="uppercase text-sm font-bold">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 class="uppercase text-sm font-bold">
|
||||
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 class="mt-2">
|
||||
{#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="uppercase font-bold">Vstupenka #{i + 1}</div>
|
||||
<div class="md:flex gap-2">
|
||||
<div class="mt-2 flex-1">
|
||||
<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 class="mt-2 flex-1">
|
||||
<div class="uppercase text-sm">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 class="uppercase text-sm">
|
||||
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 class="mt-2">
|
||||
<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 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">
|
||||
{#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}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -448,12 +629,30 @@
|
|||
{/each}
|
||||
</div>
|
||||
<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">
|
||||
{#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}
|
||||
<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 class="mt-8">
|
||||
|
@ -461,67 +660,113 @@
|
|||
<div class="mt-2">
|
||||
{#each $apiStatus.config.paymentMethods as pm}
|
||||
<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>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
<table cellpadding="5" class="table-auto">
|
||||
<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>
|
||||
</tr>
|
||||
{#if extrasStats.sum > 0}
|
||||
{#each extrasStats.arr as es}
|
||||
<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>
|
||||
</tr>
|
||||
{/each}
|
||||
{/if}
|
||||
{#if tip > 0}
|
||||
<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>
|
||||
</tr>
|
||||
{/if}
|
||||
<tr>
|
||||
<th align="right">Celkem:</th>
|
||||
<th class="font-bold">{totalPrice} Kč<th>
|
||||
</tr>
|
||||
<th class="font-bold">{totalPrice} Kč</th><th /></tr
|
||||
>
|
||||
</table>
|
||||
</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 class="mt-6">
|
||||
<div class="flex gap-3">
|
||||
{#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 formProcessing}
|
||||
<div class="flex gap-3">
|
||||
<div class=""><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 class="">
|
||||
<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>
|
||||
{/if}
|
||||
</div>
|
||||
{#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}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
<!--pre>{JSON.stringify($orderTicketForm, null, 2)}</pre>
|
||||
<pre>{JSON.stringify(extrasStats, null, 2)}</pre -->
|
||||
{/if}
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
|
|
Načítá se…
Odkázat v novém úkolu