Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • clickable-select-chevron
  • feat/new-image-formats
  • master
  • 1.2.0
  • 1.4.0
  • 1.4.1
  • 1.4.2
  • 1.5.0
  • 1.5.1
  • 1.5.2
  • 1.5.3
  • 1.5.4
  • 1.5.5
  • 1.6.0
  • 1.6.1
  • 1.6.2
  • 1.6.3
  • 1.6.4
  • 1.7.0
  • 1.8.0
  • 2.0.0
  • 2.0.0-alpha-1
  • 2.0.0-alpha-10
  • 2.0.0-alpha-11
  • 2.0.0-alpha-12
  • 2.0.0-alpha-13
  • 2.0.0-alpha-14
  • 2.0.0-alpha-15
  • 2.0.0-alpha-16
  • 2.0.0-alpha-17
  • 2.0.0-alpha-2
  • 2.0.0-alpha-3
  • 2.0.0-alpha-4
  • 2.0.0-alpha-5
  • 2.0.0-alpha-6
  • 2.0.0-alpha-7
  • 2.0.0-alpha-8
  • 2.0.0-alpha-9
  • 2.0.1
  • 2.0.2
  • 2.0.3
  • 2.0.4
  • 2.1.0
  • 2.1.1
  • 2.1.2
  • 2.10.0
  • 2.11.0
  • 2.12.1
  • 2.13.0
  • 2.14.0
  • 2.15.0
  • 2.16.0
  • 2.16.1
  • 2.17.0
  • 2.18.0
  • 2.19.0
  • 2.2.0
  • 2.2.1
  • 2.20.0
  • 2.3.0
  • 2.3.1
  • 2.3.2
  • 2.3.3
  • 2.3.4
  • 2.4.0
  • 2.5.0
  • 2.5.1
  • 2.5.2
  • 2.6.0
  • 2.7.0
  • 2.7.1
  • 2.8.0
  • 2.9.0
  • 2.9.1
74 results

Target

Select target project
  • to/weby/ui-styleguide
  • va-fighters/ui-styleguide
2 results
Select Git revision
  • master
  • 1.2.0
  • 1.4.0
  • 1.4.1
  • 1.4.2
  • 1.5.0
  • 1.5.1
  • 1.5.2
  • 1.5.3
  • 1.5.4
  • 1.5.5
  • 1.6.0
  • 1.6.1
  • 1.6.2
  • 1.6.3
  • 1.6.4
  • 1.7.0
  • 1.8.0
  • 2.0.0-alpha-1
  • 2.0.0-alpha-10
  • 2.0.0-alpha-11
  • 2.0.0-alpha-2
  • 2.0.0-alpha-3
  • 2.0.0-alpha-4
  • 2.0.0-alpha-5
  • 2.0.0-alpha-6
  • 2.0.0-alpha-7
  • 2.0.0-alpha-8
  • 2.0.0-alpha-9
29 results
Show changes
Showing
with 1209 additions and 126 deletions
<script>
const initialEvents = [
{
id: 2,
start: "2020-07-08T10:00:00.000Z",
startTimestamp: new Date("2020-07-08T10:00:00.000Z").getTime(),
startDateVerbose: "středa 8. července 2020",
startTimeVerbose: "12:00",
allDay: false,
end: "2020-07-08T11:00:00.000Z",
title: "Pirátský oběd - Chrudim",
description:
"Pravidelné setkání pirátů při středečním obědě. Nejen o politice a s chutí.",
link:
"https://www.google.com/calendar/event?eid=Mmw1Y2RwMTByYm80Y204cWxsaW1maWJmcTJfMjAyMDA3MDhUMTAwMDAwWiA3cjY3M3JsaDI1NW9mb3JodjNvZWIybDBnMEBn"
},
{
id: 15,
start: "2020-07-13T19:00:00.000Z",
startTimestamp: new Date("2020-07-13T19:00:00.000Z").getTime(),
startDateVerbose: "pondělí 13. července 2020",
startTimeVerbose: "21:00",
allDay: false,
end: "2020-07-13T19:30:00.000Z",
title: "Mumble - předsednictvo",
link:
"https://www.google.com/calendar/event?eid=YzVpM2FvaGc2MHAzY2I5aGM1aW1jYjlrNjBvbThiYjE2dGk2NGI5ajY4cjY0ZGhrNzVnamdjOWdjb18yMDIwMDcxM1QxOTAwMDBaIDdyNjczcmxoMjU1b2Zvcmh2M29lYjJsMGcwQGc"
},
{
id: 3,
start: "2020-07-15T10:00:00.000Z",
startTimestamp: new Date("2020-07-15T10:00:00.000Z").getTime(),
startDateVerbose: "středa 15. července 2020",
startTimeVerbose: "12:00",
allDay: false,
end: "2020-07-15T11:00:00.000Z",
title: "Pirátský oběd - Chrudim",
description:
"Pravidelné setkání pirátů při středečním obědě. Nejen o politice a s chutí.",
link:
"https://www.google.com/calendar/event?eid=Mmw1Y2RwMTByYm80Y204cWxsaW1maWJmcTJfMjAyMDA3MTVUMTAwMDAwWiA3cjY3M3JsaDI1NW9mb3JodjNvZWIybDBnMEBn",
mapLink: "https://maps.google.com"
},
{
id: 16,
start: "2020-07-20T19:00:00.000Z",
startTimestamp: new Date("2020-07-20T19:00:00.000Z").getTime(),
startDateVerbose: "pondělí 20. července 2020",
startTimeVerbose: "21:00",
allDay: false,
end: "2020-07-20T19:30:00.000Z",
title: "Mumble - předsednictvo",
link:
"https://www.google.com/calendar/event?eid=YzVpM2FvaGc2MHAzY2I5aGM1aW1jYjlrNjBvbThiYjE2dGk2NGI5ajY4cjY0ZGhrNzVnamdjOWdjb18yMDIwMDcyMFQxOTAwMDBaIDdyNjczcmxoMjU1b2Zvcmh2M29lYjJsMGcwQGc"
},
{
id: 4,
start: "2020-07-22T10:00:00.000Z",
startTimestamp: new Date("2020-07-22T10:00:00.000Z").getTime(),
startDateVerbose: "středa 22. července 2020",
startTimeVerbose: "12:00",
allDay: false,
end: "2020-07-22T11:00:00.000Z",
title: "Pirátský oběd - Chrudim",
description:
"Pravidelné setkání pirátů při středečním obědě. Nejen o politice a s chutí.",
link:
"https://www.google.com/calendar/event?eid=Mmw1Y2RwMTByYm80Y204cWxsaW1maWJmcTJfMjAyMDA3MjJUMTAwMDAwWiA3cjY3M3JsaDI1NW9mb3JodjNvZWIybDBnMEBn"
},
{
id: 17,
start: "2020-07-27T19:00:00.000Z",
startTimestamp: new Date("2020-07-27T19:00:00.000Z").getTime(),
startDateVerbose: "pondělí 27. července 2020",
startTimeVerbose: "21:00",
allDay: false,
end: "2020-07-27T19:30:00.000Z",
title: "Mumble - předsednictvo",
link:
"https://www.google.com/calendar/event?eid=YzVpM2FvaGc2MHAzY2I5aGM1aW1jYjlrNjBvbThiYjE2dGk2NGI5ajY4cjY0ZGhrNzVnamdjOWdjb18yMDIwMDcyN1QxOTAwMDBaIDdyNjczcmxoMjU1b2Zvcmh2M29lYjJsMGcwQGc"
},
{
id: 5,
start: "2020-07-29T10:00:00.000Z",
startTimestamp: new Date("2020-07-29T10:00:00.000Z").getTime(),
startDateVerbose: "středa 29. července 2020",
startTimeVerbose: "12:00",
allDay: false,
end: "2020-07-29T11:00:00.000Z",
title: "Pirátský oběd - Chrudim",
description:
"Pravidelné setkání pirátů při středečním obědě. Nejen o politice a s chutí.",
link:
"https://www.google.com/calendar/event?eid=Mmw1Y2RwMTByYm80Y204cWxsaW1maWJmcTJfMjAyMDA3MjlUMTAwMDAwWiA3cjY3M3JsaDI1NW9mb3JodjNvZWIybDBnMEBn"
},
{
id: 18,
start: "2020-08-03T19:00:00.000Z",
startTimestamp: new Date("2020-08-03T19:00:00.000Z").getTime(),
startDateVerbose: "pondělí 3. srpna 2020",
startTimeVerbose: "21:00",
allDay: false,
end: "2020-08-03T19:30:00.000Z",
title: "Mumble - předsednictvo",
link:
"https://www.google.com/calendar/event?eid=YzVpM2FvaGc2MHAzY2I5aGM1aW1jYjlrNjBvbThiYjE2dGk2NGI5ajY4cjY0ZGhrNzVnamdjOWdjb18yMDIwMDgwM1QxOTAwMDBaIDdyNjczcmxoMjU1b2Zvcmh2M29lYjJsMGcwQGc"
},
{
id: 6,
start: "2020-08-05T10:00:00.000Z",
startTimestamp: new Date("2020-08-05T10:00:00.000Z").getTime(),
startDateVerbose: "středa 5. srpna 2020",
startTimeVerbose: "12:00",
allDay: false,
end: "2020-08-05T11:00:00.000Z",
title: "Pirátský oběd - Chrudim",
description:
"Pravidelné setkání pirátů při středečním obědě. Nejen o politice a s chutí.",
link:
"https://www.google.com/calendar/event?eid=Mmw1Y2RwMTByYm80Y204cWxsaW1maWJmcTJfMjAyMDA4MDVUMTAwMDAwWiA3cjY3M3JsaDI1NW9mb3JodjNvZWIybDBnMEBn"
}
];
const moreEvents = [
{
id: 19,
start: "2020-08-10T19:00:00.000Z",
startTimestamp: new Date("2020-08-10T19:00:00.000Z").getTime(),
startDateVerbose: "pondělí 10. srpna 2020",
startTimeVerbose: "21:00",
allDay: false,
end: "2020-08-10T19:30:00.000Z",
title: "Mumble - předsednictvo",
link:
"https://www.google.com/calendar/event?eid=YzVpM2FvaGc2MHAzY2I5aGM1aW1jYjlrNjBvbThiYjE2dGk2NGI5ajY4cjY0ZGhrNzVnamdjOWdjb18yMDIwMDgxMFQxOTAwMDBaIDdyNjczcmxoMjU1b2Zvcmh2M29lYjJsMGcwQGc"
},
{
id: 7,
start: "2020-08-12T10:00:00.000Z",
startTimestamp: new Date("2020-08-12T10:00:00.000Z").getTime(),
startDateVerbose: "středa 12. srpna 2020",
startTimeVerbose: "12:00",
allDay: false,
end: "2020-08-12T11:00:00.000Z",
title: "Pirátský oběd - Chrudim",
description:
"Pravidelné setkání pirátů při středečním obědě. Nejen o politice a s chutí.",
link:
"https://www.google.com/calendar/event?eid=Mmw1Y2RwMTByYm80Y204cWxsaW1maWJmcTJfMjAyMDA4MTJUMTAwMDAwWiA3cjY3M3JsaDI1NW9mb3JodjNvZWIybDBnMEBn"
}
];
export default {
data: () => ({
events: initialEvents,
hasMore: true,
}),
methods: {
onShowMore() {
this.$data.events = [...initialEvents, ...moreEvents];
this.$data.hasMore = false;
}
},
render() {
return this.$scopedSlots.default({
events: this.events,
hasMore: this.hasMore,
onShowMore: this.onShowMore,
});
}
};
</script>
<script>
const pageSize = 10;
export default {
props: {
calendarId: {
type: String,
required: true,
},
apiKey: {
type: String,
required: true,
}
},
data() {
return {
events: [],
toShow: 7,
};
},
computed: {
displayedEvents() {
return this.events.slice(0, this.toShow);
},
hasMore() {
return this.toShow < this.events.length;
},
},
methods: {
onShowMore() {
this.toShow += pageSize;
},
loadEventsFromStorage() {
if (window.sessionStorage && window.sessionStorage['__pircal_' + this.calendarId]) {
return JSON.parse(window.sessionStorage['__pircal_' + this.calendarId]);
}
},
// Store events to sessionStorage if possible to save requests.
storeEventsToStorage() {
if (window.sessionStorage) {
window.sessionStorage['__pircal_' + this.calendarId] = JSON.stringify(this.events);
}
}
},
mounted() {
const ev = this.loadEventsFromStorage();
if (! ev) {
const toIso = now => now.toISOString().split('.')[0]+"Z";
const now = new Date();
const timeMin = now.toISOString();
const timeMax = new Date(+now + (1000 * 60 * 60 * 24 * 90)).toISOString(); // 90 days ahead
const reqUrl = `https://www.googleapis.com/calendar/v3/calendars/${this.calendarId}/events?key=${encodeURIComponent(this.apiKey)}&maxResults=150&timeMin=${encodeURIComponent(timeMin)}&timeMax=${encodeURIComponent(timeMax)}&sanitizeHtml=true&singleEvents=true&maxAtendees=1`;
let counter = 0;
fetch(reqUrl)
.then(response => {
if (!response.ok) {
throw new Error("Problem loading events from google");
}
return response.json()
})
.then(resp => {
this.events = resp.items
.map(e => {
const start = new Date(e.start.dateTime || e.start.date);
const end = new Date(e.end.dateTime || e.end.date);
const startDateVerbose = start.toLocaleDateString('cs-CZ', {weekday: 'long', year: 'numeric', month: 'long', day: 'numeric'});
const startTimeVerbose = start.getHours() + ':' + start.getMinutes().toString().padStart(2, '0');
const allDay = ! e.start.dateTime;
return {
id: counter++,
start: start,
startTimestamp: start.getTime(),
startDateVerbose,
startTimeVerbose,
allDay,
end: end,
title: e.summary,
description: e.description,
link: e.htmlLink
};
})
.sort((e1, e2) => e1.start < e2.start ? -1 : 1);
this.storeEventsToStorage();
});
} else {
this.events = ev;
}
},
render() {
return this.$scopedSlots.default({
events: this.displayedEvents,
hasMore: this.hasMore,
onShowMore: this.onShowMore,
});
}
};
</script>
<template>
<div class="calendar grid grid-cols-4">
<div v-if="showBanner" class="col-span-4 xl:col-span-1">
<aside class="banner bg-orange-300 text-white h-full">
<i class="ico--calendar banner__icon"></i>
<div class="banner__body">
<h1 class="head-alt-md banner__cta">{{ name }}</h1>
<button class="btn btn--white btn--fullwidth sm:btn--autowidth mt-8" v-if="onShowMore && hasMore" @click="onShowMore()">
<div class="btn__body">Zobrazit další</div>
</button>
</div>
</aside>
</div>
<div :class="{'col-span-4 xl:col-span-3': showBanner, 'col-span-4': !showBanner}">
<div class="grid grid-cols-12 items-center calendar-table-row" v-for="event in events" v-bind:key="event.id" :class="{'calendar-table-row--standalone': !showBanner}">
<div class="col-span-2 text-orange-300 head-alt-md calendar-table-row__col"><span>{{ event.startTimestamp | dateDay }}</span></div>
<div class="col-span-8 grid grid-cols-3 col-gap-4 calendar-table-row__col" :class="{'calendar-table-row__col--norborder': !event.mapLink}">
<div class="col-span-3 md:col-span-1">
<strong class="block">{{ event.startDateVerbose }}</strong>
<p class="font-light text-sm mt-1">{{ event.allDay ? "Celý den" : event.startTimeVerbose }}</p>
</div>
<div class="col-span-3 md:col-span-2 mt-4 md:mt-0">
<a v-if="event.link" v-bind:href="event.link" class="font-bold block" target="_blank" rel="noreferrer noopener">{{ event.title }}</a>
<strong v-if="!event.link" class="block">{{ event.title }}</strong>
<p class="font-light text-sm mt-1" v-if="event.description">{{ event.description }}</p>
</div>
</div>
<div class="col-span-2 text-center font-light calendar-table-row__col">
<a :href="event.mapLink" v-if="event.mapLink" class="icon-link">
<i class="ico--location text-violet-300 mr-1" aria-hidden="true"></i>
<span>Mapa</span>
</a>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
name: {
type: String,
default: "Kalendář"
},
events: {
type: Array,
required: true,
},
onShowMore: {
type: Function,
required: false,
},
hasMore: {
type: Boolean,
default: true,
},
showBanner: {
type: Boolean,
default: true,
},
},
filters: {
dateDay: (val) => {
return `${new Date(val).getDate()}.`;
}
}
};
</script>
<template>
<div :class="[wrapperclass, 'footer-collapsible']">
<span class="text-xl uppercase text-white footer-collapsible__toggle" :class="[labelclass, show ? 'footer-collapsible__toggle--open' : '']" @click="handleClick">{{ label }}</span>
<div v-show="show || isLgScreenSize" :class="[slotwrapperclass]">
<slot>
</slot>
</div>
</div>
</template>
<script>
import { isLgScreenSize } from "../../utils";
export default {
data() {
return {
isLgScreenSize: isLgScreenSize(),
show: false,
resizeHandler: () => {
this.$data.isLgScreenSize = isLgScreenSize();
},
};
},
props: {
href: {
type: String,
},
label: {
type: String,
},
labelclass: {
type: String,
},
wrapperclass: {
type: String,
default: "",
},
slotwrapperclass: {
type: String,
default: "",
}
},
methods: {
handleClick() {
if (this.$props.href) {
window.location = this.$props.href;
}
this.$data.show = !this.$data.show;
}
},
mounted() {
this.$nextTick(() => {
window.addEventListener("resize", this.$data.resizeHandler);
});
},
beforeDestroy() {
window.removeEventListener("resize", this.$data.resizeHandler);
}
}
</script>
<script>
import FullCalendar from "@fullcalendar/vue"
import dayGridPlugin from "@fullcalendar/daygrid"
import { showEventData } from './utils'
export default {
components: {
FullCalendar // make the <FullCalendar> tag available
},
props: ["events"],
data() {
return {
calendarOptions: {
plugins: [ dayGridPlugin ],
initialView: "dayGridMonth",
contentHeight: "auto",
locale: "cs",
buttonText: {
today: "dnes"
},
eventTimeFormat: {
hour: 'numeric',
minute: '2-digit',
meridiem: false
},
moreLinkContent: (arg) => { return `+${arg.num} další` },
eventClick (info) {
showEventData(info)
},
events: JSON.parse(this.events)
}
}
}
}
</script>
<template>
<FullCalendar :options="calendarOptions" />
</template>
<script>
import FullCalendar from "@fullcalendar/vue"
import dayGridPlugin from "@fullcalendar/daygrid"
import multiMonthPlugin from "@fullcalendar/multimonth"
import { showEventData } from './utils'
export default {
components: {
FullCalendar // make the <FullCalendar> tag available
},
props: ["events"],
data() {
return {
calendarOptions: {
plugins: [ dayGridPlugin, multiMonthPlugin ],
initialView: "multiMonthYear",
contentHeight: "auto",
locale: "cs",
buttonText: {
today: "dnes"
},
moreLinkContent: (arg) => { return `+${arg.num} další` },
eventClick (info) {
showEventData(info)
},
events: JSON.parse(this.events)
}
}
}
}
</script>
<template>
<FullCalendar :options="calendarOptions" />
</template>
import tippy from 'tippy.js';
const showEventData = (info) => {
if (
info.event.url === ''
&& info.event.extendedProps.location === undefined
&& info.event.extendedProps.url === undefined
) {
return
}
info.jsEvent.preventDefault();
const popup = tippy(
info.el,
{
content: `
<div class="p-2 flex flex-col gap-3 text-white whitespace-nowrap">
${
(info.event.title !== undefined) ?
`
<div class="flex gap-2 items-baseline">
<div>${info.event.title}</div>
</div>
` : ''
}
${
(info.event.extendedProps.location !== undefined) ?
`
<div class="flex gap-2 items-baseline">
<i class="ico--location" aria-label="Místo konání"></i>
<div>${info.event.extendedProps.location}</div>
</div>
` : ''
}
${
(info.event.extendedProps.description !== undefined) ?
`
<div class="flex gap-2 items-baseline">
<i class="ico--info" aria-label="Popis"></i>
<div>${info.event.extendedProps.description}</div>
</div>
` : ''
}
${
(info.event.url !== '') ?
`
<div class="flex gap-2 items-baseline">
<i class="ico--link" aria-label="Adresa"></i>
<a class="underline cursor-pointer" href="${info.event.url}">${info.event.url}</a>
</div>
` : ''
}
</div>
`,
trigger: (
(
info.event.url !== ''
&& info.event.extendedProps.location === undefined
&& info.event.extendedProps.url === undefined
) ?
'hover' : 'click'
),
allowHTML: true,
interactive: true
}
);
popup.show();
}
export { showEventData }
<script>
import UiNavbarSubitem from "./NavbarSubitem";
import UiNavbarSubitemReplacing from "./NavbarSubitemReplacing";
import { isLgScreenSize } from "../../utils";
export default {
components: {
UiNavbarSubitem,
UiNavbarSubitemReplacing,
},
data() {
return {
isLgScreenSize: isLgScreenSize(),
show: false,
resizeHandler: () => {
this.$data.isLgScreenSize = isLgScreenSize();
},
};
},
mounted() {
this.$nextTick(() => {
window.addEventListener("resize", this.$data.resizeHandler);
});
},
beforeDestroy() {
window.removeEventListener("resize", this.$data.resizeHandler);
}
}
</script>
<template>
<div @mouseenter="onMouseEnter" @mouseleave="onMouseLeave">
<span v-if="!href" class="navbar-menu__link navbar-menu__submenu-toggle" :class="{'navbar-menu__submenu-toggle--open': show}" @click="handleClick">{{ label }}</span>
<a v-if="href" :href="href" class="navbar-menu__link navbar-menu__submenu-toggle" :class="{'navbar-menu__submenu-toggle--open': show}" @click.prevent="handleClick">{{ label }}</a>
<div :class="{'navbar-menu__submenu-wrap--show': show}" class="navbar-menu__submenu-wrap">
<slot>
</slot>
</div>
</div>
</template>
<script>
import { isLgScreenSize } from "../../utils";
export default {
data() {
return {
show: false
};
},
props: {
href: {
type: String,
},
label: {
type: String,
}
},
methods: {
onMouseEnter() {
if (isLgScreenSize()) {
this.$data.show = true;
}
},
onMouseLeave() {
if (isLgScreenSize()) {
this.$data.show = false;
}
},
handleClick(evt) {
// On mobile screens, first click should just toggle and redir on second one
if (isLgScreenSize() || this.$data.show) {
if (this.$props.href) {
window.location = this.$props.href;
}
}
this.$data.show = !this.$data.show;
}
}
}
</script>
<template>
<div @mouseenter="onMouseEnter" @mouseleave="onMouseLeave">
<span v-if="!href" class="navbar-menu__link navbar-menu__submenu-toggle" :class="{'navbar-menu__submenu-toggle--open': show}" @click="handleClick">{{ label }}</span>
<a v-if="href" :href="href" class="navbar-menu__link navbar-menu__submenu-toggle" :class="{'navbar-menu__submenu-toggle--open': show}" @click.prevent="handleClick">{{ label }}</a>
<div :class="{'navbar-menu__submenu-wrap--show': show}" class="navbar-menu__submenu-wrap">
<ul class="navbar-menu__submenu">
<li v-for="(item, index) in parsedItems" :key="index">
<a :href="item[1]" class="navbar-menu__link">{{ item[0] }}</a>
</li>
</ul>
</div>
</div>
</template>
<script>
import { isLgScreenSize } from "../../utils";
export default {
data() {
return {
show: false,
parsedItems: JSON.parse(this.items),
};
},
props: {
href: {
type: String,
},
label: {
type: String,
},
items: {
type: String,
}
},
methods: {
onMouseEnter() {
if (isLgScreenSize()) {
this.$data.show = true;
}
},
onMouseLeave() {
if (isLgScreenSize()) {
this.$data.show = false;
}
},
handleClick(evt) {
// On mobile screens, first click should just toggle and redir on second one
if (isLgScreenSize() || this.$data.show) {
if (this.$props.href) {
window.location = this.$props.href;
}
}
this.$data.show = !this.$data.show;
}
}
}
</script>
document.addEventListener('DOMContentLoaded', function () {
import Vue from "vue";
import { forEachNode } from "./utils";
import Renderer from "./components/calendar/Renderer";
import DummyProvider from "./components/calendar/DummyProvider";
import GoogleProvider from "./components/calendar/GoogleProvider"
import MonthCalendar from "./components/full-calendar/MonthCalendar";
import YearCalendar from "./components/full-calendar/YearCalendar";
import RegionMap from "./components/RegionMap";
import ViewProvider from "./components/ViewProvider";
import Navbar from "./components/navbar/Navbar";
import FooterCollapsible from "./components/footer/FooterCollapsible";
import FlipClock from "./components/FlipClock";
import Chart from 'chart.js/auto';
Vue.component("ui-calendar-renderer", Renderer);
Vue.component("ui-calendar-dummy-provider", DummyProvider);
Vue.component("ui-calendar-google-provider", GoogleProvider);
Vue.component("ui-month-calendar", MonthCalendar);
Vue.component("ui-year-calendar", YearCalendar);
Vue.component("ui-region-map", RegionMap);
Vue.component("ui-view-provider", ViewProvider);
Vue.component("ui-navbar", Navbar);
Vue.component("ui-footer-collapsible", FooterCollapsible);
Vue.component("ui-flip-clock", FlipClock);
import UiApp from "./components/UiApp.vue";
const appFactory = (el, attrs) => {
// Bootstrap Vue.js.
new Vue({
el,
components: {
UiApp
}
});
};
/**
* Bootstrap Vue.js application at given Element instance.
*
* App properties are passed via data attributes, like:
*
* <div class="__vue-root" data-message="Hello" data-app="SomeApp"></div>
*
* @param {Element} el DOM Element
*/
function renderVueAppElement(el) {
const attrs = Object.assign({}, el.dataset);
return appFactory(el, attrs);
}
function renderChart(element) {
const data = [
{ year: 2010, count: 10 },
{ year: 2011, count: 20 },
{ year: 2012, count: 15 },
{ year: 2013, count: 25 },
{ year: 2014, count: 22 },
{ year: 2015, count: 30 },
{ year: 2016, count: 28 },
];
new Chart(
element,
{
type: 'bar',
data: {
labels: data.map(row => row.year),
datasets: [
{
label: 'Firemní akvizice každý rok',
data: data.map(row => row.count)
}
]
}
}
);
}
function init(event) {
// Initialize Vue.js apps.
forEachNode(document.querySelectorAll('.__js-root'), renderVueAppElement)
// Show example charts.
forEachNode(document.querySelectorAll('.__chart-example'), renderChart);
}
document.addEventListener('DOMContentLoaded', init);
import screens from "../../screens";
const lgScreenSize = parseInt(screens.lg.replace("px", ""), 10);
export const forEachNode = function (array, callback, scope) {
for (var i = 0; i < array.length; i++) {
callback.call(scope, array[i]); // passes back stuff we need
}
};
export function getWindowWidth() {
return Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
}
export function isLgScreenSize() {
return getWindowWidth() >= lgScreenSize;
}
const _ = require('lodash');
const Color = require('color');
// const defaultConfig = require('tailwindcss/defaultConfig')();
const darken = (clr, val) => Color(clr).darken(val).rgb().string();
const lighten = (clr, val) => Color(clr).lighten(val).rgb().string();
function defaultOptions() {
return {
textAlign: 'center',
display: 'inline-block',
fontWeight: '400',
maxWidth: '20rem',
colors: {},
}
}
module.exports = function (options) {
options = _.isFunction(options)
? options(defaultOptions())
: _.defaults(options, defaultOptions());
return function ({ addComponents, addUtilities, e, theme }) {
const getThemeColor = (alias, fallback) => {
if (!alias) {
return fallback;
}
return theme(`colors.${alias}`);
}
const btnUtilities = {
'.btn.btn--fullwidth': {
width: '100%',
maxWidth: '100%',
'.btn__body-wrap': {
width: '100%',
maxWidth: '100%',
},
'.btn__body': {
flex: '1'
}
},
'.btn.btn--autowidth': {
width: 'auto',
}
};
addUtilities(btnUtilities, ['responsive']);
const defaultIconBorder = getThemeColor(options.defaultColor.iconBorder, lighten(getThemeColor(options.defaultColor.background, '#000'), 0.1));
addComponents([
{
'.btn': {
display: 'inline-block',
textAlign: 'center',
display: 'inline-block',
fontWeight: theme('fontWeight.normal'),
maxWidth: theme('maxWidth.xs'),
textDecoration: 'none',
},
'.btn[disabled]': {
opacity: '0.7',
cursor: 'not-allowed',
},
'.btn:hover': {
textDecoration: 'none',
},
'.btn__body': {
display: 'flex',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
padding: '.75em 2em'
},
'.btn__icon': {
display: 'flex',
alignItems: 'center',
borderLeftWidth: '1px',
padding: `0 ${theme('spacing.4')}`,
borderColor: defaultIconBorder,
},
// All possible parts are transition ready
'.btn__body, .btn__icon, .btn__inline-icon': {
transitionProperty: 'color,background-color,border-color',
transitionDuration: '.2s',
color: getThemeColor(options.defaultColor.text),
},
'.btn__body, .btn__icon': {
backgroundColor: getThemeColor(options.defaultColor.background),
},
'.btn__icon img': {
width: theme('spacing.4')
},
// Button with a standalone icon on right side
'.btn--icon .btn__body-wrap': {
display: 'flex',
},
// Button with a standalone icon on the left
'.btn--inverted-icon .btn__icon': {
order: '-1',
borderRightWidth: '1px',
borderLeftWidth: '0',
},
// Button with an inline icon
'.btn__inline-icon': {
marginRight: theme('spacing.2'),
},
// Smaller size
'.btn--condensed .btn__body': {
padding: '.75em 1em',
},
'@keyframes btn-loading-spinner': {
'to': {
transform: 'rotate(360deg)',
}
},
'.btn--loading': {
position: 'relative',
},
'.btn--loading::before': {
pointerEvents: 'none',
content: "''",
position: 'absolute',
left: '0',
right: '0',
top: '0',
bottom: '0',
zIndex: '2',
backgroundColor: theme('colors.black'),
opacity: '0.4',
},
'.btn--loading::after': {
pointerEvents: 'none',
content: "''",
position: 'absolute',
left: '0',
right: '0',
top: '0',
bottom: '0',
zIndex: '3',
top: '50%',
left: '50%',
width: '1.5rem',
height: '1.5rem',
marginTop: '-0.75rem',
marginLeft: '-0.75rem',
borderRadius: '50%',
border: `3px solid ${theme('colors.cyan.200')}`,
borderLeftColor: 'transparent',
animation: 'btn-loading-spinner 1s linear infinite',
}
},
..._.map(options.colors, (colorOptions, name) => {
const bg = getThemeColor(colorOptions.background, '#000');
return {
// Standard colorized variant
[`.btn--${e(name)} .btn__body, .btn--${e(name)} .btn__icon`]: {
backgroundColor: getThemeColor(colorOptions.background),
color: getThemeColor(colorOptions.text),
},
[`.btn--${e(name)} .btn__icon`]: {
borderColor: getThemeColor(colorOptions.iconBorder, darken(bg, 0.1)),
backgroundColor: getThemeColor(colorOptions.iconBackground, bg),
},
// Hover state unless set with --to-* variant.
[`.btn--${e(name)}.btn--hoveractive:not([class^="btn--to-"]):hover`]: {
'.btn__body, .btn__icon': {
backgroundColor: getThemeColor(colorOptions.hoverBackground, darken(bg, 0.2)),
color: getThemeColor(colorOptions.hoverText, '#fff'),
},
'.btn__icon': {
borderColor: getThemeColor(
colorOptions.hoverIconBorder,
darken(bg, 0.3)
),
},
'.btn__icon svg, .btn__icon i': {
color: getThemeColor(colorOptions.hoverText, '#fff'),
fill: getThemeColor(colorOptions.hoverText, '#fff')
}
},
[`.btn--hoveractive.btn--to-${e(name)}:hover, .btn--to-${e(name)}.btn--activated`]: {
'.btn__body': {
backgroundColor: `${getThemeColor(colorOptions.background)} !important`,
color: `${getThemeColor(colorOptions.text)} !important`,
},
'.btn__icon': {
borderColor: `${getThemeColor(colorOptions.iconBorder, darken(getThemeColor(colorOptions.background, '#000'), 0.1))} !important`,
backgroundColor: `${getThemeColor(colorOptions.iconBackground, getThemeColor(colorOptions.background, '#000'))} !important`,
},
'.btn__inline-icon': {
color: `${getThemeColor(colorOptions.text)} !important`,
}
}
}
})
])
}
}
const Color = require('color');
const screens = require("./screens");
const alpha = (clr, val) => Color(clr).alpha(val).rgb().string();
const lighen = (clr, val) => Color(clr).lighten(val).rgb().string();
const darken = (clr, val) => Color(clr).darken(val).rgb().string();
module.exports = {
content: [
"./source/**/*.mustache",
"./source/**/*.json",
"./source/**/*.js",
"./source/**/*.vue",
"./public/**/*.html",
],
options: {
whitelistPatterns: [
/^((sm|md|lg|xl)\:)?(block|inline|fixed|absolute|inline-block|flex|inline-flex|grid)/,
/^((sm|md|lg|xl)\:)?w-\d\d?/,
/^((sm|md|lg|xl)\:)?w-(auto|full|screen)/,
/^((sm|md|lg|xl)\:)?h-\d\d?/,
/^((sm|md|lg|xl)\:)?h-screen/,
/^((sm|md|lg|xl)\:)?-?m.?-\d\d?/,
/^((sm|md|lg|xl)\:)?-?m.?-auto?/,
/^((sm|md|lg|xl)\:)?p.?-\d\d?/,
/^((sm|md|lg|xl)\:)?space-.?-\d\d?/,
/^((sm|md|lg|xl)\:)?hidden/,
/^((sm|md|lg|xl)\:)?block/,
/^((sm|md|lg|xl)\:)?inline-block/,
/^((sm|md|lg|xl)\:)?flex/,
/^((sm|md|lg|xl)\:)?inline-flex/,
/^((sm|md|lg|xl)\:)?grid/,
/^((sm|md|lg|xl)\:)?gap-\d\d?/,
/^((sm|md|lg|xl)\:)?static/,
/^((sm|md|lg|xl)\:)?flex-row-*/,
/^((sm|md|lg|xl)\:)?flex-col-*/,
/^((sm|md|lg|xl)\:)?grid-cols-*/,
/^((sm|md|lg|xl)\:)?col-span-*/,
/^((sm|md|lg|xl)\:)?row-span-*/,
/^((sm|md|lg|xl)\:)?order-*/,
/^((sm|md|lg|xl)\:)?items-*/,
/^((sm|md|lg|xl)\:)?float-*/,
/^((sm|md|lg|xl|hover)\:)?text-*/,
/^((sm|md|lg|xl)\:)?grid-flow-*/,
/^((sm|md|lg|xl)\:)?head-*/,
/^((sm|md|lg|xl)\:)?clearfix/,
/^((sm|md|lg|xl|hover)\:)?elevation-*/,
/^((sm|md|lg|xl|hover)\:)?border(-.*)?/,
/^((sm|md|lg|xl|hover)\:)?bg-opacity-\d\d?/,
/whitespace-*/,
/opacity-*/,
/^truncate/,
/^break-*/,
/^overflow-*/,
/^duration-*/,
/^max-w-*/,
/^max-h-*/,
/ico--*/,
],
},
theme: {
extend: {
maxWidth: {
'xxs': '16rem',
},
gridTemplateColumns: {
'candidate-table-row': 'auto auto auto auto 1fr'
height: {
'120': '30rem',
},
opacity: {
'85': '0.85',
......@@ -15,27 +74,27 @@ module.exports = {
},
spacing: {
'0/5': '0.125rem',
'14': '3.5rem',
'28': '7rem',
'36': '9rem',
'44': '11rem',
'52': '13rem',
'80': '20rem'
}
'80': '20rem',
},
// Breakpoints
screens: {
'sm': '576px',
'md': '768px',
'lg': '992px',
'xl': '1200px',
'2xl': '1366px',
// flip-x
scale: {
'-1': '-1',
},
},
// Breakpoints
screens,
fontFamily: {
alt: ['Bebas Neue', 'Helvetica', 'Arial', 'sans-serif'],
body: ['Roboto', 'Helvetica', 'Arial', 'sans-serif'],
condensed: ['Roboto Condensed', 'Helvetica', 'Arial', 'sans-serif'],
},
fontSize: {
'2xs': '.65rem',
'xs': '.75rem',
'sm': '.875rem',
'base': '1rem',
......@@ -46,7 +105,9 @@ module.exports = {
'4xl': '2.45rem',
'5xl': '3rem',
'6xl': '4rem',
'7xl': '5.6rem',
'7xl': '5.3rem',
'8xl': '6.5rem',
'9xl': '7.5rem',
},
fontWeight: {
light: 300,
......@@ -59,10 +120,10 @@ module.exports = {
'black': '#000000',
'white': '#ffffff',
'grey': {
'25': '#fafafa',
'50': '#f7f7f7',
'100': '#f3f3f3',
'125': '#f0f0f0',
'150': '#00000012',
'200': '#adadad',
'300': '#4c4c4c',
'400': '#343434',
......@@ -71,43 +132,60 @@ module.exports = {
'700': '#202020',
'800': '#1f1f1f',
},
'red': {
'100': '#d6151b',
'olive': {
'100': '#d6e8b3'
},
'green': {
'100': '#29bc51',
'200': '#26b34b',
'300': '#22a244',
'200': '#92c6ab',
'300': '#76cc9f',
'400': '#4ca971',
},
'yellow': {
'100': '#fff7bf',
'200': '#f7f38a',
'300': '#ffea5a',
'400': '#fde119',
},
'red': {
'600': '#d60d53'
},
'brands': {
'facebook': '#067ceb',
'twitter': '#00c9ff',
'gmail': '#ec230e',
'linkedin': '#0066a9',
}
},
// spacing: {
// '0': '0',
// 'xs': '0.15rem',
// 'sm': '0.25rem',
// '1': '0.5rem',
// '2': '1rem',
// '3': '1.5rem',
// '4': '2rem',
// '5': '2.5rem',
// '6': '3rem',
// '7': '4rem',
// '8': '6rem',
// '9': '8rem',
// '10': '10rem',
// '11': '12rem',
// '11': '16rem',
// '12': '20rem',
// '13': '24rem',
// '14': '30rem',
// },
'blue': {
'100': '#abcdef',
'200': '#76b4cf',
'300': '#027da8',
},
'cyan': {
'100': '#a7d4d1',
'200': '#57b3bd',
'300': '#3e8793',
'400': '#497280',
'500': '#004958',
},
'orange': {
'100': '#f2d29f',
'200': '#f1ae7b',
'300': '#ed9654',
},
'violet': {
'100': '#edc8bd',
'200': '#d28c94',
'300': '#8d415f',
'400': '#840048',
'500': '#670047',
},
'pirati': {
'yellow': '#fec934'
},
},
container: {
center: true,
/* @note: needs to be kept in sync with tailwind css/atoms/container.pcss */
padding: {
default: '1rem',
xl: '2rem',
......@@ -120,90 +198,12 @@ module.exports = {
},
variants: {
textDecorationColor: ['responsive', 'hover'],
background: ['responsive'],
appearance: ['responsive'],
space: ['responsive'],
text: ['responsive', 'hover'],
zIndex: ['responsive'],
},
// textStyles: theme => ({ // defaults to {}
// heading: {
// output: false, // this means there won't be a "heading" component in the CSS, but it can be extended
// fontWeight: theme('fontWeight.bold'),
// lineHeight: theme('lineHeight.tight'),
// },
// h1: {
// extends: 'heading', // this means all the styles in "heading" will be copied here; "extends" can also be an array to extend multiple text styles
// fontSize: theme('fontSize.5xl'),
// '@screen sm': {
// fontSize: theme('fontSize.6xl'),
// },
// },
// h2: {
// extends: 'heading',
// fontSize: theme('fontSize.4xl'),
// '@screen sm': {
// fontSize: theme('fontSize.5xl'),
// },
// },
// h3: {
// extends: 'heading',
// fontSize: theme('fontSize.4xl'),
// },
// h4: {
// extends: 'heading',
// fontSize: theme('fontSize.3xl'),
// },
// h5: {
// extends: 'heading',
// fontSize: theme('fontSize.2xl'),
// },
// h6: {
// extends: 'heading',
// fontSize: theme('fontSize.xl'),
// },
// link: {
// '&:hover': {
// textDecoration: 'underline',
// },
// },
// richText: {
// fontWeight: theme('fontWeight.normal'),
// fontSize: theme('fontSize.base'),
// lineHeight: theme('lineHeight.relaxed'),
// '> * + *': {
// marginTop: '1em',
// },
// 'h1': {
// extends: 'h1',
// },
// 'h2': {
// extends: 'h2',
// },
// 'h3': {
// extends: 'h3',
// },
// 'h4': {
// extends: 'h4',
// },
// 'h5': {
// extends: 'h5',
// },
// 'h6': {
// extends: 'h6',
// },
// 'ul': {
// listStyleType: 'disc',
// },
// 'ol': {
// listStyleType: 'decimal',
// },
// 'a': {
// extends: 'link',
// },
// 'b, strong': {
// fontWeight: theme('fontWeight.bold'),
// },
// 'i, em': {
// fontStyle: 'italic',
// },
// },
// }),
plugins: [
require('tailwind-css-variables')(
{
......@@ -213,7 +213,7 @@ module.exports = {
// options
}
),
require('tailwindcss-typography')({
require('@tailwindcss/typography')({
// all these options default to the values specified here
ellipsis: false, // whether to generate ellipsis utilities
hyphens: false, // whether to generate hyphenation utilities
......@@ -225,5 +225,81 @@ module.exports = {
color: "#dddddd",
opacityBoost: '0.23',
}),
require("./tailwind-plugins/buttons")({
defaultColor: {
text: 'white',
background: 'black',
iconBorder: 'grey.300'
},
colors: {
'black': {
text: 'white',
background: 'black',
iconBorder: 'grey.400',
hoverIconBorder: 'grey.600',
},
'grey-700': {
text: 'white',
background: 'grey.700',
iconBorder: 'grey.500',
hoverBackground: 'grey.400',
hoverIconBorder: 'grey.600',
},
'grey-500': {
text: 'white',
background: 'grey.500',
iconBorder: 'grey.300',
hoverBackground: 'grey.300',
hoverIconBorder: 'grey.400',
},
'grey-125': {
text: 'black',
background: 'grey.125',
hoverText: 'black',
},
'white': {
text: 'black',
background: 'white',
iconBorder: 'grey.100',
hoverText: 'black',
},
'blue-300': {
text: 'white',
background: 'blue.300',
},
'cyan-200': {
text: 'white',
background: 'cyan.200',
},
'green-300': {
text: 'white',
background: 'green.300',
},
'green-400': {
text: 'white',
background: 'green.400',
},
'orange-300': {
text: 'white',
background: 'orange.300',
},
'violet-400': {
text: 'white',
background: 'violet.400',
},
'violet-500': {
text: 'white',
background: 'violet.500',
},
'red-600': {
text: 'white',
background: 'red.600',
},
'brands-facebook': {
text: 'white',
background: 'brands.facebook',
}
}
})
]
}