diff --git a/district/blocks.py b/district/blocks.py index 2e0bff8b7cebb0d618c604c8fadb5868aa140c50..a1fb75c8175da9d5a20ead1eb4f9429554d2b1cb 100644 --- a/district/blocks.py +++ b/district/blocks.py @@ -31,10 +31,47 @@ class AddressBlock(StructBlock): label = "Adresa" +class SimplePersonBlock(StructBlock): + title = blocks.CharBlock(label="Jméno a příjmení", max_length=128, required=True) + job = blocks.CharBlock( + label="Povolání", max_length=128, required=False, help_text="Např. 'Informatik'" + ) + profile_photo = ImageChooserBlock(label="Profilová fotka", required=False) + email = blocks.EmailBlock(label="Email", required=False) + city = blocks.CharBlock(label="Město/obec", max_length=64, required=False) + age = blocks.IntegerBlock(label="Věk", required=False) + is_pirate = blocks.BooleanBlock( + label="Je členem Pirátské strany?", default=True, required=False + ) + other_party = blocks.CharBlock(label="Strana", max_length=64, required=False) + other_party_logo = ImageChooserBlock( + label="Logo strany", required=False, help_text="Vyplňte pokud osoba není Pirát" + ) + + # socials + facebook_url = blocks.URLBlock(label="Odkaz na Facebook", required=False) + instagram_url = blocks.URLBlock(label="Odkaz na Instagram", required=False) + twitter_url = blocks.URLBlock(label="Odkaz na Twitter", required=False) + youtube_url = blocks.URLBlock(label="Odkaz na Youtube kanál", required=False) + flickr_url = blocks.URLBlock(label="Odkaz na Flickr", required=False) + + class Meta: + icon = "user" + label = "Osoba blok" + + class CandidateListBlock(StructBlock): - candidate_list = ListBlock( - PageChooserBlock(label="Osoba", page_type=["district.DistrictPersonPage"]), + candidate_list = blocks.StreamBlock( label="Kandidáti", + local_blocks=[ + ( + "person_page", + PageChooserBlock( + label="Osoba", page_type=["district.DistrictPersonPage"] + ), + ), + ("person_block", SimplePersonBlock()), + ], ) candidate_list_big_count = IntegerBlock( label="Počet kanditátů s velkým náhledem", default=7 diff --git a/district/migrations/0094_alter_districtelectioncampaignpage_candidates.py b/district/migrations/0094_alter_districtelectioncampaignpage_candidates.py new file mode 100644 index 0000000000000000000000000000000000000000..216b07030308c2c1f78803af87794dee12417350 --- /dev/null +++ b/district/migrations/0094_alter_districtelectioncampaignpage_candidates.py @@ -0,0 +1,252 @@ +# Generated by Django 4.0.4 on 2022-07-22 07:53 + +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks +from django.db import migrations +from wagtail.core.blocks import StreamValue + + +def person_chooser_list_block_to_compact_block(block): + for person_page in block["value"]["candidate_list"]: + person_page["type"] = "person_page" + return block + + +def compact_block_to_person_chooser_list_block(block): + for (index, compact_block) in enumerate(block["value"]["candidate_list"]): + if compact_block["type"] == "person_page": + compact_block["type"] = "item" + else: + del block["value"]["candidate_list"][index] + + return block + + +def get_content(page, mapper): + stream_data = [] + mapped = False + + for block in page.candidates.raw_data: + if block["type"] == "candidates": + stream_data.append(mapper(block)) + mapped = True + else: + stream_data.append(block) + + return stream_data, mapped + + +def migrate(apps, mapper): + DistrictElectionCampaignPage = apps.get_model( + "district", "DistrictElectionCampaignPage" + ) + + for page in DistrictElectionCampaignPage.objects.all(): + candidates, mapped = get_content(page, mapper) + + if mapped: + page.candidates = StreamValue(page.candidates, candidates, is_lazy=True) + page.save() + + +def forwards(apps, schema_editor): + migrate(apps, person_chooser_list_block_to_compact_block) + + +def backwards(apps, schema_editor): + migrate(apps, compact_block_to_person_chooser_list_block) + + +class Migration(migrations.Migration): + + dependencies = [ + ("district", "0093_alter_districthomepage_subheader"), + ] + + operations = [ + migrations.AlterField( + model_name="districtelectioncampaignpage", + name="candidates", + field=wagtail.fields.StreamField( + [ + ( + "candidates", + wagtail.blocks.StructBlock( + [ + ( + "candidate_list", + wagtail.blocks.StreamBlock( + [ + ( + "person_page", + wagtail.blocks.PageChooserBlock( + label="Osoba", + page_type=[ + "district.DistrictPersonPage" + ], + ), + ), + ( + "person_block", + wagtail.blocks.StructBlock( + [ + ( + "title", + wagtail.blocks.CharBlock( + label="Jméno a příjmení", + max_length=128, + required=True, + ), + ), + ( + "job", + wagtail.blocks.CharBlock( + help_text="Např. 'Informatik'", + label="Povolání", + max_length=128, + required=False, + ), + ), + ( + "profile_photo", + wagtail.images.blocks.ImageChooserBlock( + label="Profilová fotka", + required=False, + ), + ), + ( + "email", + wagtail.blocks.EmailBlock( + label="Email", + required=False, + ), + ), + ( + "city", + wagtail.blocks.CharBlock( + label="Město/obec", + max_length=64, + required=False, + ), + ), + ( + "age", + wagtail.blocks.IntegerBlock( + label="Věk", + required=False, + ), + ), + ( + "is_pirate", + wagtail.blocks.BooleanBlock( + default=True, + label="Je členem Pirátské strany?", + required=False, + ), + ), + ( + "other_party", + wagtail.blocks.CharBlock( + label="Strana", + max_length=64, + required=False, + ), + ), + ( + "other_party_logo", + wagtail.images.blocks.ImageChooserBlock( + help_text="Vyplňte pokud osoba není Pirát", + label="Logo strany", + required=False, + ), + ), + ( + "facebook_url", + wagtail.blocks.URLBlock( + label="Odkaz na Facebook", + required=False, + ), + ), + ( + "instagram_url", + wagtail.blocks.URLBlock( + label="Odkaz na Instagram", + required=False, + ), + ), + ( + "twitter_url", + wagtail.blocks.URLBlock( + label="Odkaz na Twitter", + required=False, + ), + ), + ( + "youtube_url", + wagtail.blocks.URLBlock( + label="Odkaz na Youtube kanál", + required=False, + ), + ), + ( + "flickr_url", + wagtail.blocks.URLBlock( + label="Odkaz na Flickr", + required=False, + ), + ), + ] + ), + ), + ], + label="Kandidáti", + ), + ), + ( + "candidate_list_big_count", + wagtail.blocks.IntegerBlock( + default=7, + label="Počet kanditátů s velkým náhledem", + ), + ), + ( + "candidate_list_shown_count", + wagtail.blocks.IntegerBlock( + default=16, + label="Počet zobrazených kandidátů při načtení stránky (včetně velkých náhledů)", + ), + ), + ( + "cta_text", + wagtail.blocks.CharBlock( + label="Text 'call-to-action' baneru", + required=False, + ), + ), + ( + "cta_link", + wagtail.blocks.URLBlock( + label="Odkaz 'call-to-action' baneru", + required=False, + ), + ), + ( + "cta_button_text", + wagtail.blocks.CharBlock( + label="Text tlačítka 'call-to-action' baneru", + max_length=24, + required=False, + ), + ), + ] + ), + ) + ], + blank=True, + use_json_field=None, + verbose_name="Kandidátní listina", + ), + ), + migrations.RunPython(forwards, backwards), + ] diff --git a/district/templates/district/blocks/candidate_list_block.html b/district/templates/district/blocks/candidate_list_block.html index 7a0a9c33dfb6f74ba6a47745c693a56f7b7e9041..ab752a967825ffa6b7db51f5f625d70f9f567877 100644 --- a/district/templates/district/blocks/candidate_list_block.html +++ b/district/templates/district/blocks/candidate_list_block.html @@ -1,11 +1,16 @@ <div class="candidate-card-list grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4"> - {% for person_page in self.candidate_list %} - {% if forloop.counter <= self.candidate_list_big_count %} - {% include "shared/full_candidate_snippet.html" %} - {% endif %} - {% endfor %} + {% for block in self.candidate_list %} + {% if forloop.counter <= self.candidate_list_big_count %} + {% if block.block_type == 'person_page' %} + {% include "shared/full_candidate_snippet.html" with person_page=block.value %} + {% endif %} + {% if block.block_type == 'person_block' %} + {% include "shared/blocks/full_candidate_snippet_block.html" with block=block.value %} + {% endif %} + {% endif %} + {% endfor %} - {% if self.cta_text%} + {% if self.cta_text %} <aside class="banner bg-black text-white container-padding--zero sm:container-padding--auto"> <i class="ico--pirati banner__icon"></i> <div class="banner__body"> @@ -27,17 +32,27 @@ <div> <ui-view-provider :initial="{fullCandidateTable: false}" v-slot="{ isCurrentView, setView }"> <div class="candidate-table pt-8 container-padding--zero lg:container-padding--auto" :class="{'candidate-table--fadeout': !isCurrentView('fullCandidateTable')}"> - {% for person_page in self.candidate_list %} + {% for block in self.candidate_list %} {# Záměrně neomezuju list přes indexy, ale ifuju, abych si držel counter pro snippet #} {% if forloop.counter > self.candidate_list_big_count and forloop.counter <= self.candidate_list_shown_count %} - {% include "shared/compact_candidate_snippet.html" %} + {% if block.block_type == 'person_page' %} + {% include "shared/compact_candidate_snippet.html" with person_page=block.value %} + {% endif %} + {% if block.block_type == 'person_block' %} + {% include "shared/blocks/compact_candidate_snippet_block.html" with block=block.value %} + {% endif %} {% endif %} {% endfor %} <template v-if="isCurrentView('fullCandidateTable')"> - {% for person_page in self.candidate_list %} + {% for block in self.candidate_list %} {# Záměrně neomezuju list přes indexy, ale ifuju, abych si držel counter pro snippet #} {% if forloop.counter > self.candidate_list_shown_count %} - {% include "shared/compact_candidate_snippet.html" %} + {% if block.block_type == 'person_page' %} + {% include "shared/compact_candidate_snippet.html" with person_page=block.value %} + {% endif %} + {% if block.block_type == 'person_block' %} + {% include "shared/blocks/compact_candidate_snippet_block.html" with block=block.value %} + {% endif %} {% endif %} {% endfor %} </template> diff --git a/shared/templates/shared/blocks/compact_candidate_snippet_block.html b/shared/templates/shared/blocks/compact_candidate_snippet_block.html new file mode 100644 index 0000000000000000000000000000000000000000..3aac6af62bacde3a52cd6b049158385f5d9d2726 --- /dev/null +++ b/shared/templates/shared/blocks/compact_candidate_snippet_block.html @@ -0,0 +1,47 @@ +{% load static wagtailimages_tags %} + +<div class="candidate-table-row"> + <div class="candidate-table-row__position head-allcaps-heavy-2xs text-right"> + <span {% if forloop.counter < 10 %}class="pl-1 pr-1"{% endif %}> + {{ forloop.counter }} + </span> + </div> + <div class="avatar avatar--sm candidate-table-row__avatar"> + {% if block.profile_photo %} + {# Match sizing of person_badge_snippet.html to keep the image version count low #} + {% image block.profile_photo fill-160x160 as profile_img %} + <img src="{{ profile_img.url }}" alt="{{ block.title }}"/> + {% else %} + <img src="{% static "shared/img/unknown_pirate_160x160.jpg" %}" alt="{{ block.title }}"/> + {% endif %} + </div> + <div class="candidate-table-row__name head-heavy-2xs font-bold"> + {{ block.title }} + </div> + <div class="candidate-table-row__bio font-condensed"> + {% if block.age %}{{ block.age }} let,{% endif %} + {% if block.job %}{{ block.job }},{% endif %} + {% if block.city %}{{ block.city }}{% endif %} + </div> + <div class="candidate-table-row__affiliation"> + <div class="flex items-center"> + {% if block.is_pirate %} + <div class="avatar w-6 mr-2"> + <img src="{% static "shared/img/logo_black.svg" %}" alt="Pirátská strana"> + </div> + <span class="font-bold font-condensed">Pirátská strana</span> + {% endif %} + + {% if not block.is_pirate and block.other_party %} + {% if block.other_party_logo %} + {% image block.other_party_logo width-48 as logo_img %} + <div class="avatar w-6 mr-2"> + <img src="{{ logo_img.url }}" alt="{{ block.other_party }}"> + </div> + {% endif %} + + <span class="font-bold font-condensed">{{ block.other_party }}</span> + {% endif %} + </div> + </div> +</div> diff --git a/shared/templates/shared/blocks/full_candidate_snippet_block.html b/shared/templates/shared/blocks/full_candidate_snippet_block.html new file mode 100644 index 0000000000000000000000000000000000000000..cff979a858bcf07167de173a87e874cc37f5ab51 --- /dev/null +++ b/shared/templates/shared/blocks/full_candidate_snippet_block.html @@ -0,0 +1,94 @@ +{% load static wagtailimages_tags %} + +<div class="candidate-card container-padding--zero sm:container-padding--auto "> + <div + class="candidate-card__wrapper candidate-card__wrapper sm:candidate-card-list__item-wrapper md:candidate-card-list__item-wrapper--border" + > + <div class="card candidate-card__body elevation-0 hover:elevation-10 transition duration-200"> + <div class="candidate-card__avatar"> + <div class="candidate-card__position"> + {{ forloop.counter }} + </div> + <div class="avatar avatar--sm sm:avatar--lg"> + {% if block.profile_photo %} + {# Match sizing of person page to keep the image version count low #} + {% image block.profile_photo fill-416x416 as profile_img %} + <img src="{{ profile_img.url }}" alt="{{ block.title }}"/> + {% else %} + <img src="{% static "shared/img/unknown_pirate_416x416.jpg" %}" alt="{{ block.title }}"/> + {% endif %} + </div> + </div> + <div class="candidate-card__bio"> + <h1 class="head-heavy-xs"> + {{ block.title }} + </h1> + {% if block.email %} + <a href="mailto:{{ block.email }}" class="block candidate-card__bio-item mb-4"> + {{ block.email }} + </a> + {% endif %} + {% if block.job %} + <h2 class=" candidate-card__bio-item"> + {{ block.job }} + </h2> + {% endif %}1 + {% if block.city %} + <h2 class="head-allcaps-4xs mt-4"> + {{ block.city }} + </h2> + {% endif %} + </div> + <div class="candidate-card__affiliation"> + {% if block.age %}<div>{{ block.age }} let</div>{% endif %} + <div class="flex items-center"> + {% if block.is_pirate %} + <div class="avatar w-6 mr-2"> + <img src="{% static "shared/img/logo_black.svg" %}" alt="Pirátská strana"> + </div> + <span class="font-bold font-condensed">Pirátská strana</span> + {% endif %} + + {% if not block.is_pirate and block.other_party %} + {% if block.other_party_logo %} + {% image block.other_party_logo width-48 as logo_img %} + <div class="avatar w-6 mr-2"> + <img src="{{ logo_img.url }}" alt="{{ block.other_party }}"> + </div> + {% endif %} + + <span class="font-bold font-condensed">{{ block.other_party }}</span> + {% endif %} + </div> + </div> + <div class="card__body candidate-card__social"> + <div class="social-icon-group space-x-2"> + {% if block.facebook_url %} + <a href="{{ block.facebook_url }}" target="_blank" class="social-icon" rel="noreferrer noopener"> + <i class="ico--facebook"></i> + </a> + {% endif %} + {% if block.instagram_url %} + <a href="{{ block.instagram_url }}" target="_blank" class="social-icon" rel="noreferrer noopener"> + <i class="ico--instagram"></i></a> + {% endif %} + {% if block.twitter_url %} + <a href="{{ block.twitter_url }}" target="_blank" class="social-icon" rel="noreferrer noopener"> + <i class="ico--twitter"></i> + </a> + {% endif %} + {% if block.youtube_url %} + <a href="{{ block.youtube_url }}" target="_blank" class="social-icon" rel="noreferrer noopener"> + <i class="ico--youtube"></i> + </a> + {% endif %} + {% if block.flickr_url %} + <a href="{{ block.flickr_url }}" target="_blank" class="social-icon" rel="noreferrer noopener"> + <i class="ico--flickr"></i> + </a> + {% endif %} + </div> + </div> + </div> + </div> +</div>