diff --git a/gulpfile.js b/gulpfile.js index 8c7b7af394123119164838581bd15800f78e0ab3..d62e87b588523cd1e55f9fe1fcecd20cb05ef376 100755 --- a/gulpfile.js +++ b/gulpfile.js @@ -33,12 +33,17 @@ const postcssPurgecss = require("@fullhuman/postcss-purgecss")({ ], defaultExtractor: (content) => content.match(/[A-Za-z0-9-_:/]+/g) || [], whitelistPatterns: [ - /^w-\d/, - /^h-\d/, - /^max-w-*/, - /^elevation-\d/, - /^text-*/, - /^ico--*/, + /(sm|md|lg|xl)?(\\:)?w-\d\d?$/, // width + /(sm|md|lg|xl)?(\\:)?h-\d\d?$/, // height + /(sm|md|lg|xl)?(\\:)m.?-\d\d?$/, // margins + /(sm|md|lg|xl)?(\\:)p.?-\d\d?$/, // paddings + /max-w-*/, // maximum width + /grid-cols-\d\d?/, // grid columns + /col-span-\d\d?/, // grid spans + /row-span-\d\d?/, // grid spans + /(sm|md|lg|xl)(\\:)text-.*/, + // /text-*/, + /^ico--[a-z]+\:before$/, // icons ], }); diff --git a/source/_patterns/01-molecules/calendar/calendar-table-row.mustache b/source/_patterns/01-molecules/calendar/calendar-table-row.mustache index 761b689727cc69be564cad69b02e283c8124c5ad..c3071ef7acafd271d2a6e3faeb7be4d254223a5c 100644 --- a/source/_patterns/01-molecules/calendar/calendar-table-row.mustache +++ b/source/_patterns/01-molecules/calendar/calendar-table-row.mustache @@ -3,11 +3,11 @@ <div class="col-span-8 grid grid-cols-3 calendar-table-row__col"> <div class="col-span-3 md:col-span-1"> <strong class="block">{{ dateverbose }}</strong> - <p class="font-light text-sm mt-sm">Celý den</p> + <p class="font-light text-sm mt-1">Celý den</p> </div> <div class="col-span-3 md:col-span-2 mt-4 md:mt-0"> <strong class="block">{{ headline.short }}</strong> - <p class="font-light text-sm mt-sm">{{ excerpt.short }}</p> + <p class="font-light text-sm mt-1">{{ excerpt.short }}</p> </div> </div> <div class="col-span-2 text-center font-light calendar-table-row__col"> diff --git a/source/_patterns/01-molecules/cards/image-card.mustache b/source/_patterns/01-molecules/cards/image-card.mustache index 48b29349f86b1154fa191e80dda37c398bde6d75..136d7f765c77219705a6a59513377c8e16491f21 100644 --- a/source/_patterns/01-molecules/cards/image-card.mustache +++ b/source/_patterns/01-molecules/cards/image-card.mustache @@ -1,6 +1,6 @@ <div class="card {{ classes }}"> <a href="#"> - <img class="w-full" src="{{ img.landscape-16x9.src }}" alt="{{ img.landscape-16x9.alt }}" /> + <img class="w-full {{ imgClasses }}" src="{{ img.landscape-16x9.src }}" alt="{{ img.landscape-16x9.alt }}" /> </a> <div class="card__body {{ bodyClasses }}"> <h1 class="card-headline mb-2"><a href="#">{{ title }}{{^ title }}{{ headline.short }}{{/ title }}</a></h1> diff --git a/source/_patterns/01-molecules/flip-clock/flip-clock.mustache b/source/_patterns/01-molecules/flip-clock/flip-clock.mustache index 8f4fea9fb4923d5272f1da775dde3370f6a2561f..4d9724dd1ce56c8bb17dc68286788da707006efd 100644 --- a/source/_patterns/01-molecules/flip-clock/flip-clock.mustache +++ b/source/_patterns/01-molecules/flip-clock/flip-clock.mustache @@ -1,4 +1,4 @@ -<div class="flip-clock __js-root"> +<div class="__js-root"> <ui-flip-clock clock-classes="{{ clockClasses }}" slot-classes="{{ slotClasses }}" diff --git a/source/_patterns/02-organisms/00-global/subnav.mustache b/source/_patterns/02-organisms/00-global/subnav.mustache index 52ef2e0f6da1367066ddf1f20e35249c0c1cf7b3..79c45c720c0cb58cf29841af8cba51d2964a01e6 100644 --- a/source/_patterns/02-organisms/00-global/subnav.mustache +++ b/source/_patterns/02-organisms/00-global/subnav.mustache @@ -1,61 +1,61 @@ <div class="__js-root"> <ui-app inline-template> - <ui-view-provider :initial="{regions: false, calendar: false}" v-slot="{ isCurrentView, toggleView }"> - <nav class="subnav"> - <div class="container container--wide"> - <div class="flex"> - <button - @click="toggleView('regions')" - class="btn btn--condensed btn--grey-500 btn--hoveractive btn--to-white text-sm mr-2" - :class="{'btn--activated': isCurrentView('regions')}" - > - <div class="btn__body"> - <span>Pardubický kraj</span> - <i class="ico--chevron-down ml-4"></i> - </div> - </button> + <ui-calendar-dummy-provider v-slot="{ events, onShowMore, hasMore }"> + <ui-view-provider :initial="{regions: false, calendar: false}" v-slot="{ isCurrentView, toggleView }"> + <nav class="subnav"> + <div class="container container--wide"> + <div class="flex"> + <button + @click="toggleView('regions')" + class="btn btn--condensed btn--grey-500 btn--hoveractive btn--to-white text-sm mr-2" + :class="{'btn--activated': isCurrentView('regions')}" + > + <div class="btn__body"> + <span>Pardubický kraj</span> + <i class="ico--chevron-down ml-4"></i> + </div> + </button> - <button - @click="toggleView('calendar')" - class="btn btn--inline-icon btn--condensed btn--hoveractive btn--grey-500 btn--to-orange-300 text-sm" - :class="{'btn--activated': isCurrentView('calendar')}" - > - <div class="btn__body"> - <i class="btn__inline-icon ico--calendar mr-0 md:mr-2 text-orange-300"></i> - <span class="hidden md:block">Krajský kalendář</span> - </div> - </button> + <button + @click="toggleView('calendar')" + class="btn btn--inline-icon btn--condensed btn--hoveractive btn--grey-500 btn--to-orange-300 text-sm" + :class="{'btn--activated': isCurrentView('calendar')}" + > + <div class="btn__body"> + <i class="btn__inline-icon ico--calendar mr-0 md:mr-2 text-orange-300"></i> + <span class="hidden md:block">Krajský kalendář</span> + </div> + </button> - <a href="#" class="btn text-sm max-w-full hidden lg:block" @click="toggleView('calendar')"> - <div class="btn__body bg-grey-800 text-grey-200 flex divide-x"> - <span class="pr-4">{{ event.title }}</span> - <span class="pl-4">{{ event.date }}</span> - </div> - </a> + <a href="#" class="btn text-sm max-w-full hidden lg:block" @click="toggleView('calendar')" v-if="events.length > 0"> + <div class="btn__body bg-grey-800 text-grey-200 flex divide-x"> + <span class="pr-4">{{events[0].title}}</span> + <span class="pl-4">{{events[0].allDay ? 'Celý den' : events[0].startDateVerbose + ', ' + events[0].startTimeVerbose}}</span> + </div> + </a> - <button class="btn btn--inline-icon btn--condensed btn--hoveractive btn--grey-500 btn--to-brands-facebook text-sm ml-2"> - <div class="btn__body"> - <i class="btn__inline-icon ico--facebook mr-0 md:mr-2 text-brands-facebook"></i> - <span class="hidden md:block">Pardubický kraj</span> + <button class="btn btn--inline-icon btn--condensed btn--hoveractive btn--grey-500 btn--to-brands-facebook text-sm ml-2"> + <div class="btn__body"> + <i class="btn__inline-icon ico--facebook mr-0 md:mr-2 text-brands-facebook"></i> + <span class="hidden md:block">Pardubický kraj</span> + </div> + </button> + </div> + </div> + </nav> + <aside class="subnav-aside"> + <div class="subnav-aside__item" :class="{'subnav-aside__item--visible': isCurrentView('regions')}"> + <a @click="toggleView('regions')" class="subnav-aside__close"><i class="ico--close"></i></a> + <ui-region-map class="container container--default"></ui-region-map> + </div> + <div class="subnav-aside__item" :class="{'subnav-aside__item--visible': isCurrentView('calendar')}"> + <a @click="toggleView('calendar')" class="subnav-aside__close"><i class="ico--close"></i></a> + <div class="container container--default"> + <ui-calendar-renderer :events="events" :on-show-more="onShowMore" :has-more="hasMore" :name="'Krajský kalendář'"></ui-calendar-renderer> </div> - </button> - </div> - </div> - </nav> - <aside class="subnav-aside"> - <div class="subnav-aside__item" :class="{'subnav-aside__item--visible': isCurrentView('regions')}"> - <a @click="toggleView('regions')" class="subnav-aside__close"><i class="ico--close"></i></a> - <ui-region-map class="container container--default"></ui-region-map> - </div> - <div class="subnav-aside__item" :class="{'subnav-aside__item--visible': isCurrentView('calendar')}"> - <a @click="toggleView('calendar')" class="subnav-aside__close"><i class="ico--close"></i></a> - <div class="container container--default"> - <ui-calendar-dummy-provider v-slot="{ events, onShowMore, hasMore }"> - <ui-calendar-renderer :events="events" :on-show-more="onShowMore" :has-more="hasMore" :name="'Krajský kalendář'"></ui-calendar-renderer> - </ui-calendar-dummy-provider> - </div> - </div> - </aside> - </ui-view-provider> + </div> + </aside> + </ui-view-provider> + </ui-calendar-dummy-provider> </ui-app> </div> diff --git a/source/_patterns/03-templates/elections.mustache b/source/_patterns/03-templates/elections.mustache index a5e6ce139c35cd38bddeba123bd610f6ad9d5cee..d335c82566932f7d2ac95f65f699dbfa30298366 100644 --- a/source/_patterns/03-templates/elections.mustache +++ b/source/_patterns/03-templates/elections.mustache @@ -67,14 +67,14 @@ <h1 class="head-alt-md text-center py-8 lg:pt-24 lg:pb-8">Volební program</h1> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> - {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", title: "Otevřenost a zapojení občanů" )}} - {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", title: "Smart city" )}} - {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", title: "Řízení a organizační struktura města" )}} - {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", title: "Rozvoj města a bydlení" )}} - {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", title: "Doprava" )}} - {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", title: "Veřejný prostor a zeleň" )}} - {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", title: "Vzdělávání" )}} - {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", title: "Kultura a volný čas" )}} + {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", imgClasses: "h-48 object-fit", title: "Otevřenost a zapojení občanů" )}} + {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", imgClasses: "h-48 object-fit", title: "Smart city" )}} + {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", imgClasses: "h-48 object-fit", title: "Řízení a organizační struktura města" )}} + {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", imgClasses: "h-48 object-fit", title: "Rozvoj města a bydlení" )}} + {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", imgClasses: "h-48 object-fit", title: "Doprava" )}} + {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", imgClasses: "h-48 object-fit", title: "Veřejný prostor a zeleň" )}} + {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", imgClasses: "h-48 object-fit", title: "Vzdělávání" )}} + {{> molecules-image-card(classes: "card--hoveractive", bodyClasses: "p-4", imgClasses: "h-48 object-fit", title: "Kultura a volný čas" )}} </div> </template> diff --git a/source/css/molecules/calendar.pcss b/source/css/molecules/calendar.pcss index dff5a32e8ca805a5aa0ba2301713f73c8a7f47db..7d24b8f7a4ac51b6520e2212a4067a0e4a389b4b 100644 --- a/source/css/molecules/calendar.pcss +++ b/source/css/molecules/calendar.pcss @@ -11,7 +11,7 @@ } .calendar-table-row__col { - @apply h-full border-r border-grey-125 p-2 flex justify-center items-center; + @apply h-full border-r border-grey-125 p-2 flex justify-center items-start; &:first-child { @apply border-l; diff --git a/source/css/molecules/candidate-card.pcss b/source/css/molecules/candidate-card.pcss index d6af350cc68a9d5cc3440a4c56781bf6a06828d8..d471722c9a242b4cbb301a09ab2d3241cfc0cc8a 100644 --- a/source/css/molecules/candidate-card.pcss +++ b/source/css/molecules/candidate-card.pcss @@ -4,6 +4,8 @@ grid-template-areas: "avatar bio" "affiliation affiliation" "social social"; + /* Needs to match .candidate-card__avatar width */ + grid-template-columns: theme("width.24") 1fr; } .candidate-card__avatar { @@ -23,10 +25,11 @@ } .candidate-card__affiliation { - @apply text-sm bg-grey-50 flex border-t border-b border-grey-125; + /* No vertical padding, proper spacing guaranteed by leading-10 - we do not expect line breaks here. */ + @apply text-sm bg-grey-50 flex border-t border-b border-grey-125 leading-10; > div { - @apply py-2 px-4 flex items-center; + @apply px-4 flex items-center; &:not(:first-child) { @apply border-l border-grey-125; @@ -69,6 +72,7 @@ @screen sm { .candidate-card { + @apply flex flex-col h-full; padding-top: 3rem; } @@ -78,10 +82,15 @@ "bio" "affiliation" "social"; + grid-template-columns: 1fr; } .candidate-card__bio { @apply p-4; + /* This adjusts the height to keep other parts (like affiliation) uniformly + aligned one to another. Adjustment is necessary in case of longer + names/descriptions. */ + min-height: 10rem; } .candidate-card__avatar { @@ -95,4 +104,8 @@ left: -0.5rem; line-height: 2.5rem; } + + .candidate-card__social { + @apply flex-grow; + } } diff --git a/source/css/molecules/candidate-table-row.pcss b/source/css/molecules/candidate-table-row.pcss index 4a43ccda2aa36d9eedc2a55eff6fc59071cf787a..230fb6a8a64110e44115a384bf24b18be99576b6 100644 --- a/source/css/molecules/candidate-table-row.pcss +++ b/source/css/molecules/candidate-table-row.pcss @@ -5,6 +5,8 @@ grid-template-areas: "position avatar name" "position avatar bio" "position avatar affiliation"; + /* Needs to match avatar width */ + grid-template-columns: auto theme("width.16") 1fr; &:after { content: ''; @@ -47,8 +49,10 @@ @screen md { .candidate-table-row { - @apply py-1 grid-cols-candidate-table-row; + @apply py-1; grid-template-areas: "position avatar name bio affiliation"; + /* Needs to match avatar width */ + grid-template-columns: auto theme("width.10") 30% 20% 1fr } .candidate-table-row__avatar { diff --git a/source/js/components/calendar/DummyProvider.vue b/source/js/components/calendar/DummyProvider.vue index d01a6aec9f1f9121f1da8861f29e1473e892138b..acb233b68d6ba9a9a4115f8b38f2d637af6ad4ce 100644 --- a/source/js/components/calendar/DummyProvider.vue +++ b/source/js/components/calendar/DummyProvider.vue @@ -2,11 +2,12 @@ const initialEvents = [ { id: 2, - start: new Date("2020-07-08T10:00:00.000Z"), + 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: new Date("2020-07-08T11:00:00.000Z"), + 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í.", @@ -15,22 +16,24 @@ const initialEvents = [ }, { id: 15, - start: new Date("2020-07-13T19:00:00.000Z"), + 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: new Date("2020-07-13T19:30:00.000Z"), + end: "2020-07-13T19:30:00.000Z", title: "Mumble - předsednictvo", link: "https://www.google.com/calendar/event?eid=YzVpM2FvaGc2MHAzY2I5aGM1aW1jYjlrNjBvbThiYjE2dGk2NGI5ajY4cjY0ZGhrNzVnamdjOWdjb18yMDIwMDcxM1QxOTAwMDBaIDdyNjczcmxoMjU1b2Zvcmh2M29lYjJsMGcwQGc" }, { id: 3, - start: new Date("2020-07-15T10:00:00.000Z"), + 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: new Date("2020-07-15T11:00:00.000Z"), + 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í.", @@ -40,22 +43,24 @@ const initialEvents = [ }, { id: 16, - start: new Date("2020-07-20T19:00:00.000Z"), + 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: new Date("2020-07-20T19:30:00.000Z"), + end: "2020-07-20T19:30:00.000Z", title: "Mumble - předsednictvo", link: "https://www.google.com/calendar/event?eid=YzVpM2FvaGc2MHAzY2I5aGM1aW1jYjlrNjBvbThiYjE2dGk2NGI5ajY4cjY0ZGhrNzVnamdjOWdjb18yMDIwMDcyMFQxOTAwMDBaIDdyNjczcmxoMjU1b2Zvcmh2M29lYjJsMGcwQGc" }, { id: 4, - start: new Date("2020-07-22T10:00:00.000Z"), + 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: new Date("2020-07-22T11:00:00.000Z"), + 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í.", @@ -64,22 +69,24 @@ const initialEvents = [ }, { id: 17, - start: new Date("2020-07-27T19:00:00.000Z"), + 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: new Date("2020-07-27T19:30:00.000Z"), + end: "2020-07-27T19:30:00.000Z", title: "Mumble - předsednictvo", link: "https://www.google.com/calendar/event?eid=YzVpM2FvaGc2MHAzY2I5aGM1aW1jYjlrNjBvbThiYjE2dGk2NGI5ajY4cjY0ZGhrNzVnamdjOWdjb18yMDIwMDcyN1QxOTAwMDBaIDdyNjczcmxoMjU1b2Zvcmh2M29lYjJsMGcwQGc" }, { id: 5, - start: new Date("2020-07-29T10:00:00.000Z"), + 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: new Date("2020-07-29T11:00:00.000Z"), + 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í.", @@ -88,22 +95,24 @@ const initialEvents = [ }, { id: 18, - start: new Date("2020-08-03T19:00:00.000Z"), + 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: new Date("2020-08-03T19:30:00.000Z"), + end: "2020-08-03T19:30:00.000Z", title: "Mumble - předsednictvo", link: "https://www.google.com/calendar/event?eid=YzVpM2FvaGc2MHAzY2I5aGM1aW1jYjlrNjBvbThiYjE2dGk2NGI5ajY4cjY0ZGhrNzVnamdjOWdjb18yMDIwMDgwM1QxOTAwMDBaIDdyNjczcmxoMjU1b2Zvcmh2M29lYjJsMGcwQGc" }, { id: 6, - start: new Date("2020-08-05T10:00:00.000Z"), + 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: new Date("2020-08-05T11:00:00.000Z"), + 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í.", @@ -115,22 +124,24 @@ const initialEvents = [ const moreEvents = [ { id: 19, - start: new Date("2020-08-10T19:00:00.000Z"), + 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: new Date("2020-08-10T19:30:00.000Z"), + end: "2020-08-10T19:30:00.000Z", title: "Mumble - předsednictvo", link: "https://www.google.com/calendar/event?eid=YzVpM2FvaGc2MHAzY2I5aGM1aW1jYjlrNjBvbThiYjE2dGk2NGI5ajY4cjY0ZGhrNzVnamdjOWdjb18yMDIwMDgxMFQxOTAwMDBaIDdyNjczcmxoMjU1b2Zvcmh2M29lYjJsMGcwQGc" }, { id: 7, - start: new Date("2020-08-12T10:00:00.000Z"), + 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: new Date("2020-08-12T11:00:00.000Z"), + 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í.", diff --git a/source/js/components/calendar/GoogleProvider.vue b/source/js/components/calendar/GoogleProvider.vue index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..06e2ff8a8de548ec449cda1b9947727542f862b1 100644 --- a/source/js/components/calendar/GoogleProvider.vue +++ b/source/js/components/calendar/GoogleProvider.vue @@ -0,0 +1,105 @@ +<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> diff --git a/source/js/components/calendar/Renderer.vue b/source/js/components/calendar/Renderer.vue index 395bf73c4c6e8374cf1a1085d08c927bd2166823..44197d1b85f0007359f63f2545263bd4d846b76a 100644 --- a/source/js/components/calendar/Renderer.vue +++ b/source/js/components/calendar/Renderer.vue @@ -13,16 +13,16 @@ </div> <div class="col-span-4 xl:col-span-3"> <div class="grid grid-cols-12 items-center calendar-table-row" v-for="event in events" v-bind:key="event.id"> - <div class="col-span-2 text-orange-300 head-alt-md calendar-table-row__col"><span>{{ event.start | dateDay }}</span></div> - <div class="col-span-8 grid grid-cols-3 calendar-table-row__col" :class="{'calendar-table-row__col--norborder': !event.mapLink}"> + <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-sm">{{ event.allDay ? "Celý den" : event.startTimeVerbose }}</p> + <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-sm" v-if="event.description">{{ event.description }}</p> + <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"> @@ -58,7 +58,7 @@ }, filters: { dateDay: (val) => { - return `${val.getDate()}.`; + return `${new Date(val).getDate()}.`; } } }; diff --git a/source/js/main.js b/source/js/main.js index 0d4dd8ba286c26a5ba716a3f63661d3dec16b40a..b42e2bfd56e423028b7bd140ad887ccf81f5fc74 100644 --- a/source/js/main.js +++ b/source/js/main.js @@ -4,6 +4,7 @@ import { forEachNode } from "./utils"; import Renderer from "./components/calendar/Renderer"; import DummyProvider from "./components/calendar/DummyProvider"; +import GoogleProvider from "./components/calendar/GoogleProvider"; import RegionMap from "./components/RegionMap"; import ViewProvider from "./components/ViewProvider"; import Navbar from "./components/navbar/Navbar"; @@ -13,6 +14,7 @@ import FlipClock from "./components/FlipClock"; Vue.component("ui-calendar-renderer", Renderer); Vue.component("ui-calendar-dummy-provider", DummyProvider); +Vue.component("ui-calendar-google-provider", GoogleProvider); Vue.component("ui-region-map", RegionMap); Vue.component("ui-view-provider", ViewProvider); Vue.component("ui-navbar", Navbar); diff --git a/tailwind.config.js b/tailwind.config.js index fdd036a65f5b9b4d224428a675ff8d943ad7c1ae..dd7c0315d09cf4adab6a64f9fe611d0dffe91279 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -11,9 +11,6 @@ module.exports = { maxWidth: { 'xxs': '16rem', }, - gridTemplateColumns: { - 'candidate-table-row': 'auto auto auto auto 1fr' - }, opacity: { '85': '0.85', }, @@ -125,6 +122,11 @@ module.exports = { }, variants: { textDecorationColor: ['responsive', 'hover'], + background: ['responsive'], + appearance: ['responsive'], + space: ['responsive'], + text: ['responsive', 'hover'], + zIndex: ['responsive'], }, plugins: [ require('tailwind-css-variables')(