From e123a904fc00a9162d1f906151a5318a1c9b5f8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Valenta?= <tomas@imaniti.org> Date: Wed, 29 May 2024 11:32:38 +0200 Subject: [PATCH] add district program type --- .../molecules/popouts/popout_point.html | 32 +++++- .../molecules/popouts/popout_point.yaml | 3 + .../header/district/center_header.html | 2 +- .../header/simple_header_with_ui_switch.html | 2 + .../templates/main/program/program.html | 95 ++++++++++++------ .../templates/main/program/program.yaml | 7 +- src/css/molecules/popout.pcss | 2 +- src/css/molecules/switch.pcss | 16 ++- src/css/organisms/newsletter.pcss | 4 - src/js/components/SecondaryViewProvider.vue | 98 +++++++++++++++++++ src/js/components/countdown/Countdown.vue | 38 +++++-- src/js/main.js | 2 + 12 files changed, 252 insertions(+), 49 deletions(-) create mode 100644 src/js/components/SecondaryViewProvider.vue diff --git a/majak_uistyleguide/templates/patterns/molecules/popouts/popout_point.html b/majak_uistyleguide/templates/patterns/molecules/popouts/popout_point.html index 8aeaa9a..287c6f2 100644 --- a/majak_uistyleguide/templates/patterns/molecules/popouts/popout_point.html +++ b/majak_uistyleguide/templates/patterns/molecules/popouts/popout_point.html @@ -4,8 +4,36 @@ {{ name }} </template> <ui-popout-content> - <div class="prose max-w-screen-lg"> - {% include "patterns/atoms/text/paragraph.html" with text=text %} + <div> + {% if guarantor_name %} + <div + class=" + !text-grey-250 [&_*]:!text-grey-250 + + mb-3 flex gap-2 items-center justify-end + " + > + <div class="mr-2"> + Garant programového bodu: + </div> + + <img + alt="Obrázek osoby {{ guarantor_name }}" + class="w-10 h-10 opacity-75 m-0 p-0 rounded-full" + src="{{ guarantor_image_url }}" + > + + <strong> + <a href="{{ guarantor_url }}"> + {{ guarantor_name }} + </a> + </strong> + </div> + {% endif %} + + <div class="prose max-w-screen-lg"> + {% include "patterns/atoms/text/paragraph.html" with text=text %} + </div> </div> </ui-popout-content> </ui-popout> diff --git a/majak_uistyleguide/templates/patterns/molecules/popouts/popout_point.yaml b/majak_uistyleguide/templates/patterns/molecules/popouts/popout_point.yaml index cc4d9dd..de8fde5 100644 --- a/majak_uistyleguide/templates/patterns/molecules/popouts/popout_point.yaml +++ b/majak_uistyleguide/templates/patterns/molecules/popouts/popout_point.yaml @@ -5,3 +5,6 @@ context: asperiores voluptatibus enim qui velit quaerat. Perspiciatis eum autem quidem et beatae quia dolore. Esse fuga architecto delectus tenetur nesciunt aut aut dolore.' + guarantor_name: 'Petr Vepřový' + guarantor_url: 'https://example.com' + guarantor_image_url: '../../../../../static/images/person-table.png' diff --git a/majak_uistyleguide/templates/patterns/organisms/header/district/center_header.html b/majak_uistyleguide/templates/patterns/organisms/header/district/center_header.html index fcec266..36c17d4 100644 --- a/majak_uistyleguide/templates/patterns/organisms/header/district/center_header.html +++ b/majak_uistyleguide/templates/patterns/organisms/header/district/center_header.html @@ -42,7 +42,7 @@ </strong> </div> - <div class="whitespace-pre">Mozilla Foundation + <div class="whitespace-pre-line">Mozilla Foundation 331 E Evelyn Ave Mountain View, CA 94041 USA</div> diff --git a/majak_uistyleguide/templates/patterns/organisms/header/simple_header_with_ui_switch.html b/majak_uistyleguide/templates/patterns/organisms/header/simple_header_with_ui_switch.html index 3ba50b3..c2b1151 100644 --- a/majak_uistyleguide/templates/patterns/organisms/header/simple_header_with_ui_switch.html +++ b/majak_uistyleguide/templates/patterns/organisms/header/simple_header_with_ui_switch.html @@ -1,5 +1,7 @@ {% extends 'patterns/organisms/header/simple_header.html' %} +{% block header_margin_class %}{% endblock %} + {% block after_description %} <div class=" diff --git a/majak_uistyleguide/templates/patterns/templates/main/program/program.html b/majak_uistyleguide/templates/patterns/templates/main/program/program.html index 96da87a..2929f0f 100644 --- a/majak_uistyleguide/templates/patterns/templates/main/program/program.html +++ b/majak_uistyleguide/templates/patterns/templates/main/program/program.html @@ -8,39 +8,74 @@ > {% include 'patterns/organisms/header/simple_header_with_ui_switch.html' with title='Program' ui_switch_iterable=programs %} - <main role="main" class="mb-4 xl:mb-20"> - <div class="container--wide flex flex-col"> - {% for program in programs %} - <template v-if="isCurrentView('view{{ forloop.counter }}')"> - {% if program.type == "concise" %} - <div> - {% if program.perex %} - <div class="mb-12"> - <div class="prose"> - {# BEGIN Cast generovana Majakem #}<div class="content-block"> - <p> - {{ program.perex }} - </p> - </div>{# END Cast generovana Majakem #} - </div> + <main role="main"> + {% for program in programs %} + <template v-if="isCurrentView('view{{ forloop.counter }}')"> + {% if program.type == "concise" %} + <div class="container--wide flex flex-col mt-20 mb-4 xl:mb-20"> + {% if program.perex %} + <div class="mb-12"> + <div class="prose"> + {# BEGIN Cast generovana Majakem #}<div class="content-block"> + <p> + {{ program.perex }} + </p> + </div>{# END Cast generovana Majakem #} </div> - {% endif %} + </div> + {% endif %} - {% include 'patterns/molecules/blocks/icon_title_text_block.html' with icon='ico--book' %} - {% include 'patterns/molecules/blocks/icon_title_text_block.html' with icon=None %} - </div> - {% elif program.type == 'popout' %} - <div class="mb-12"> - {% include 'patterns/organisms/popouts/popout_list.html' %} - </div> - {% elif program.type == 'crossroad' %} - <div class="mb-12"> - {% include 'patterns/organisms/cards/card_list.html' with description_classes="!bg-grey-180" classes='drop-shadow' %} + {% include 'patterns/molecules/blocks/icon_title_text_block.html' with icon='ico--book' %} + {% include 'patterns/molecules/blocks/icon_title_text_block.html' with icon=None %} + </div> + {% elif program.type == 'popout' %} + <div class="container--wide flex flex-col mt-20 mb-12 xl:mb-20"> + {% include 'patterns/organisms/popouts/popout_list.html' %} + </div> + {% elif program.type == 'crossroad' %} + <div class="container--wide flex flex-col mt-20 mb-12 xl:mb-20"> + {% include 'patterns/organisms/cards/card_list.html' with description_classes="!bg-grey-180" classes='drop-shadow' %} + </div> + {% elif program.type == 'with_candidates' %} + <ui-secondary-view-provider + :initial="{candidates: true, program: false}" + :sync-location="true" + v-slot="{ isCurrentSecondaryView, toggleSecondaryView }" + > + <div class="bg-white py-12 container--wide text-center"> + <a + @click="toggleSecondaryView('candidates')" + class="switch__item--program" + :class="{'switch__item--active': isCurrentSecondaryView('candidates')}" + >Kandidáti</a> + + <a + @click="toggleSecondaryView('program')" + class="switch__item--program" + :class="{'switch__item--active': isCurrentSecondaryView('program')}" + >Program</a> </div> - {% endif %} - </template> - {% endfor %} - </div> + + <template v-if="isCurrentSecondaryView('candidates')"> + <div> + {% include "patterns/organisms/candidates/elections/candidate_primary_list.html" %} + {% include "patterns/organisms/candidates/district/candidate_secondary_list.html" %} + </div> + </template> + + <template v-if="isCurrentSecondaryView('program')"> + <div class="bg-grey-50 pb-4 xl:pb-20"> + <div class="container--wide flex flex-col mb-12 gap-8"> + {% include 'patterns/atoms/text/richtext.html' %} + + {% include 'patterns/organisms/popouts/popout_list.html' %} + </div> + </div> + </template> + </ui-secondary-view-provider> + {% endif %} + </template> + {% endfor %} </main> </ui-view-provider> </div> diff --git a/majak_uistyleguide/templates/patterns/templates/main/program/program.yaml b/majak_uistyleguide/templates/patterns/templates/main/program/program.yaml index 6dd6995..4d7b0cd 100644 --- a/majak_uistyleguide/templates/patterns/templates/main/program/program.yaml +++ b/majak_uistyleguide/templates/patterns/templates/main/program/program.yaml @@ -20,4 +20,9 @@ context: name: 'dlouhodobý' type: 'popout' perex: 'Lorem ipsum dolor sit amet 5, který vysvětluje důležitost dlouhodobého - programu.' + programu.' + - + name: 'krajský' + type: 'with_candidates' + perex: 'Lorem ipsum dolor sit amet 6, který vysvětluje důležitost dlouhodobého + programu.' diff --git a/src/css/molecules/popout.pcss b/src/css/molecules/popout.pcss index 06b87e5..8639c4a 100644 --- a/src/css/molecules/popout.pcss +++ b/src/css/molecules/popout.pcss @@ -11,7 +11,7 @@ } .popout__content-wrapper { - @apply px-5 py-4 flex flex-col gap-3; + @apply px-5 py-4 flex flex-col gap-3 bg-grey-150; } .popout__toggle-arrow { diff --git a/src/css/molecules/switch.pcss b/src/css/molecules/switch.pcss index 989d301..667b574 100644 --- a/src/css/molecules/switch.pcss +++ b/src/css/molecules/switch.pcss @@ -2,7 +2,7 @@ @apply py-5 mx-auto; } -.switch__item, .switch__item--elections { +.switch__item, .switch__item--elections, .switch__item--program { @apply whitespace-nowrap cursor-pointer px-5 py-2 mb-2 font-normal text-center duration-200; &:not(:last-child) { @@ -24,6 +24,20 @@ } +.switch__item--program { + @apply bg-grey-150 text-black; + + &:hover { + @apply no-underline bg-grey-200; + } + + &.switch__item--active, + &.switch__item--active:hover { + @apply bg-pirati-yellow; + } +} + + .switch__item--elections { @apply bg-black text-white; diff --git a/src/css/organisms/newsletter.pcss b/src/css/organisms/newsletter.pcss index f25366f..3a55396 100644 --- a/src/css/organisms/newsletter.pcss +++ b/src/css/organisms/newsletter.pcss @@ -1,10 +1,6 @@ .newsletter-section { @apply bg-cover bg-no-repeat; - &:not(.newsletter-section--small) { - background-position: -400px; - } - @screen md { background-position: left top; } diff --git a/src/js/components/SecondaryViewProvider.vue b/src/js/components/SecondaryViewProvider.vue new file mode 100644 index 0000000..67d45ca --- /dev/null +++ b/src/js/components/SecondaryViewProvider.vue @@ -0,0 +1,98 @@ +<template> + <div> + <slot + v-bind:secondaryViews="secondaryViews" + v-bind:isCurrentSecondaryView="isCurrentSecondaryView" + v-bind:toggleSecondaryView="toggleSecondaryView" + v-bind:showSecondaryView="showSecondaryView" + v-bind:setSecondaryView="setSecondaryView" + ></slot> + </div> +</template> + +<script> +export default { + props: { + initial: { + default: () => {} + }, + syncLocation: { + type: Boolean, + default: false, + }, + locationParam: { + type: String, + default: "secondary-view", + } + }, + data() { + return { + secondaryViews: this.$props.initial, + queryParams: null, + keyListener: e => { + // Esc + if (e.keyCode === 27) { + this.hideAllViews(); + } + } + }; + }, + watch: { + routeView() { + const queryParams = new URLSearchParams(window.location.search); + } + }, + methods: { + setSecondaryView(viewId, show, hideOthers = false) { + if (hideOthers) { + Object.keys(this.$data.secondaryViews).forEach(key => { + if (key !== viewId) { + this.setSecondaryView(key, false); + } + }); + } + + this.$data.secondaryViews[viewId] = show; + + if (show && this.$props.syncLocation) { + const queryParams = new URLSearchParams(window.location.search); + + queryParams.set(this.$props.locationParam, viewId); + history.pushState(null, null, "?" + queryParams.toString()); + } + }, + setSecondaryViews(updates) { + this.$data.secondaryViews = Object.assign({}, this.data.secondaryViews, updates); + }, + toggleSecondaryView(viewId) { + !this.isCurrentSecondaryView(viewId) && this.setSecondaryView(viewId, !this.isCurrentSecondaryView(viewId), true); + }, + showSecondaryView(viewId) { + this.setSecondaryView(viewId, true, true); + }, + isCurrentSecondaryView(viewId) { + return this.$data.secondaryViews[viewId]; + }, + hideAllViews() { + Object.keys(this.$data.secondaryViews).forEach(key => { + this.setSecondaryView(key, false); + }); + } + }, + mounted() { + window.addEventListener('keydown', this.$data.keyListener); + + if (this.$props.syncLocation) { + const queryParams = new URLSearchParams(window.location.search); + const locationView = queryParams.get(this.$props.locationParam); + + if (locationView && Object.keys(this.$data.secondaryViews).indexOf(locationView) !== -1) { + this.showSecondaryView(locationView); + } + } + }, + destroyed() { + window.removeEventListener('keydown', this.$data.keyListener); + } +} +</script> diff --git a/src/js/components/countdown/Countdown.vue b/src/js/components/countdown/Countdown.vue index ca15798..afd9714 100644 --- a/src/js/components/countdown/Countdown.vue +++ b/src/js/components/countdown/Countdown.vue @@ -29,6 +29,34 @@ export default { }, methods: { updateCountdown() { + const formatCountdown = (countdown) => { + let parts = []; + + if (countdown.days > 0) { + parts.push(`${countdown.days} dní`); + } + if (countdown.hours > 0) { + parts.push(`${countdown.hours} hodin`); + } + if (countdown.minutes > 0) { + parts.push(`${countdown.minutes} minut`); + } + + // Always include seconds + parts.push(`${countdown.seconds} sekund`); + + // Determine pluralization for "sekund" + let secondsSuffix = ''; + + if (countdown.seconds === 1) { + secondsSuffix = 'a'; + } else if (countdown.seconds > 1 && countdown.seconds < 5) { + secondsSuffix = 'y'; + } + + return parts.join(', ') + (parts.length > 0 ? secondsSuffix : ''); + } + const targetDate = new Date(this.to); const currentDate = new Date(); @@ -51,15 +79,7 @@ export default { this.countdown.seconds = Math.floor(timeDifference / 1000); - // Determine pluralization for "sekund" - let secondsSuffix = ''; - if (this.countdown.seconds === 1) { - secondsSuffix = 'a'; - } else if (this.countdown.seconds > 1 && this.countdown.seconds < 5) { - secondsSuffix = 'y'; - } - - this.countdownText = `${this.countdown.days} dní, ${this.countdown.hours} hodin, ${this.countdown.minutes} minut a ${this.countdown.seconds} sekund${secondsSuffix}`; + this.countdownText = formatCountdown(this.countdown); } } }; diff --git a/src/js/main.js b/src/js/main.js index 7bd0fd4..25404be 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -14,6 +14,7 @@ import GoogleProvider from "./components/calendar/GoogleProvider"; import FullCalendar from "./components/full_calendar/Calendar"; import RegionMap from "./components/RegionMap"; import ViewProvider from "./components/ViewProvider"; +import SecondaryViewProvider from "./components/SecondaryViewProvider"; import Popout from "./components/popout/Popout"; import PopoutContent from "./components/popout/PopoutContent"; import PopoutItem from "./components/popout/PopoutItem"; @@ -35,6 +36,7 @@ Vue.component("ui-calendar-google-provider", GoogleProvider); Vue.component("ui-full-calendar", FullCalendar); Vue.component("ui-region-map", RegionMap); Vue.component("ui-view-provider", ViewProvider); +Vue.component("ui-secondary-view-provider", SecondaryViewProvider); Vue.component("ui-popout", Popout); Vue.component("ui-popout-content", PopoutContent); Vue.component("ui-popout-item", PopoutItem); -- GitLab