diff --git a/network-api/networkapi/templates/fragments/responsive_screen_wide_image.html b/network-api/networkapi/templates/fragments/responsive_screen_wide_image.html index d48548f65db..977d4733b29 100644 --- a/network-api/networkapi/templates/fragments/responsive_screen_wide_image.html +++ b/network-api/networkapi/templates/fragments/responsive_screen_wide_image.html @@ -1,4 +1,4 @@ -{% load wagtailimages_tags %} +{% load wagtailimages_tags i18n %} diff --git a/network-api/networkapi/wagtailpages/migrations/0133_appinstallpage.py b/network-api/networkapi/wagtailpages/migrations/0133_appinstallpage.py new file mode 100644 index 00000000000..163326b21d9 --- /dev/null +++ b/network-api/networkapi/wagtailpages/migrations/0133_appinstallpage.py @@ -0,0 +1,150 @@ +# Generated by Django 4.2.11 on 2024-04-03 00:02 + +import django.db.models.deletion +import wagtail.blocks +import wagtail.documents.blocks +import wagtail.fields +import wagtail.images.blocks +from django.db import migrations, models + +import networkapi.wagtailpages.validators + + +class Migration(migrations.Migration): + + dependencies = [ + ("wagtailimages", "0025_alter_image_file_alter_rendition_file"), + ("wagtailpages", "0132_make_link_to_required_in_link_block"), + ] + + operations = [ + migrations.CreateModel( + name="AppInstallPage", + fields=[ + ( + "campaignpage_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="wagtailpages.campaignpage", + ), + ), + ("hero_heading", models.CharField(help_text="Hero story headline", max_length=80)), + ("hero_subheading", models.CharField(blank=True, help_text="Hero story subheadline", max_length=80)), + ( + "hero_video", + models.URLField( + blank=True, + help_text="To find embed link: go to your YouTube video and click “Share,” then “Embed,” and then copy and paste the provided URL only. EX: https://www.youtube.com/embed/3FIVXBawyQ", + null=True, + ), + ), + ( + "download_buttons", + wagtail.fields.StreamField( + [ + ( + "button", + wagtail.blocks.StructBlock( + [ + ("label", wagtail.blocks.CharBlock()), + ( + "link_to", + wagtail.blocks.ChoiceBlock( + choices=[ + ("page", "Page"), + ("external_url", "External URL"), + ("relative_url", "Relative URL"), + ("email", "Email"), + ("anchor", "Anchor"), + ("file", "File"), + ("phone", "Phone"), + ], + label="Link to", + ), + ), + ("page", wagtail.blocks.PageChooserBlock(label="Page", required=False)), + ( + "external_url", + wagtail.blocks.URLBlock( + help_text="Enter a full URL including http:// or https://", + label="External URL", + max_length=300, + required=False, + ), + ), + ( + "relative_url", + wagtail.blocks.CharBlock( + help_text='A path relative to this domain. For example, "/foo/bar"', + label="Relative URL", + max_length=300, + required=False, + validators=[networkapi.wagtailpages.validators.RelativeURLValidator()], + ), + ), + ( + "anchor", + wagtail.blocks.CharBlock( + help_text='An id attribute of an element on the current page. For example, "#section-1"', + label="#", + max_length=300, + required=False, + validators=[networkapi.wagtailpages.validators.AnchorLinkValidator()], + ), + ), + ("email", wagtail.blocks.EmailBlock(required=False)), + ( + "file", + wagtail.documents.blocks.DocumentChooserBlock( + label="File", required=False + ), + ), + ( + "phone", + wagtail.blocks.CharBlock(label="Phone", max_length=30, required=False), + ), + ( + "new_window", + wagtail.blocks.BooleanBlock(label="Open in new window", required=False), + ), + ( + "icon", + wagtail.images.blocks.ImageChooserBlock( + help_text="For best results, please use black or white icons.", + required=False, + ), + ), + ( + "icon_alt_text", + wagtail.blocks.CharBlock( + help_text="Image description (for screen readers).", required=False + ), + ), + ] + ), + ) + ], + blank=True, + use_json_field=True, + ), + ), + ( + "hero_background", + models.ForeignKey( + help_text="Background image for the hero section", + on_delete=django.db.models.deletion.PROTECT, + related_name="+", + to="wagtailimages.image", + ), + ), + ], + options={ + "abstract": False, + }, + bases=("wagtailpages.campaignpage",), + ), + ] diff --git a/network-api/networkapi/wagtailpages/models.py b/network-api/networkapi/wagtailpages/models.py index bccbd890a7c..4dce3c774ef 100644 --- a/network-api/networkapi/wagtailpages/models.py +++ b/network-api/networkapi/wagtailpages/models.py @@ -1,4 +1,5 @@ # flake8: noqa +from .pagemodels.app_install import AppInstallPage from .pagemodels.base import ( FocusArea, FoundationMetadataPageMixin, diff --git a/network-api/networkapi/wagtailpages/pagemodels/app_install.py b/network-api/networkapi/wagtailpages/pagemodels/app_install.py new file mode 100644 index 00000000000..9cfac4c13f4 --- /dev/null +++ b/network-api/networkapi/wagtailpages/pagemodels/app_install.py @@ -0,0 +1,81 @@ +from django.db import models +from wagtail.admin.panels import FieldPanel, InlinePanel, MultiFieldPanel +from wagtail.fields import StreamField +from wagtail_localize.fields import SynchronizedField, TranslatableField + +from .campaigns import CampaignPage +from .customblocks.app_install_download_button_block import ( + AppInstallDownloadButtonBlock, +) + + +class AppInstallPage(CampaignPage): + + zen_nav = False + + hero_heading = models.CharField( + max_length=80, + help_text="Hero story headline", + ) + hero_subheading = models.CharField( + max_length=80, + blank=True, + help_text="Hero story subheadline", + ) + hero_background = models.ForeignKey( + "wagtailimages.Image", + on_delete=models.PROTECT, + related_name="+", + help_text="Background image for the hero section", + ) + hero_video = models.URLField( + null=True, + blank=True, + help_text="To find embed link: go to your YouTube video and click “Share,” then “Embed,” " + "and then copy and paste the provided URL only. EX: https://www.youtube.com/embed/3FIVXBawyQ", + ) + download_buttons = StreamField( + [ + ("button", AppInstallDownloadButtonBlock()), + ], + use_json_field=True, + max_num=2, + blank=True, + ) + + content_panels = [ + FieldPanel("title"), + MultiFieldPanel( + [ + FieldPanel("hero_background"), + FieldPanel("hero_heading"), + FieldPanel("hero_subheading"), + FieldPanel("download_buttons"), + FieldPanel("hero_video"), + ], + heading="Hero Section", + ), + MultiFieldPanel( + [ + FieldPanel("cta"), + InlinePanel("donation_modals", label="Donation Modal", max_num=4), + FieldPanel("body"), + ], + heading="Page Content", + ), + ] + + translatable_fields = CampaignPage.translatable_fields + [ + SynchronizedField("hero_background"), + TranslatableField("hero_heading"), + TranslatableField("hero_subheading"), + TranslatableField("download_buttons"), + SynchronizedField("hero_video"), + ] + + subpage_types = [ + "BanneredCampaignPage", + "OpportunityPage", + ] + + parent_page_types = ["BanneredCampaignPage", "Homepage"] diff --git a/network-api/networkapi/wagtailpages/pagemodels/base.py b/network-api/networkapi/wagtailpages/pagemodels/base.py index aeb43066548..b40e7c67d70 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/base.py +++ b/network-api/networkapi/wagtailpages/pagemodels/base.py @@ -959,6 +959,7 @@ def get_banner(self): ] subpage_types = [ + "AppInstallPage", "BanneredCampaignPage", "BlogIndexPage", "CampaignIndexPage", diff --git a/network-api/networkapi/wagtailpages/pagemodels/campaigns.py b/network-api/networkapi/wagtailpages/pagemodels/campaigns.py index 54ca2608d4c..fc2d3953472 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/campaigns.py +++ b/network-api/networkapi/wagtailpages/pagemodels/campaigns.py @@ -427,6 +427,7 @@ class BanneredCampaignPage(PrimaryPage): ] subpage_types = [ + "AppInstallPage", "BanneredCampaignPage", "PublicationPage", "OpportunityPage", diff --git a/network-api/networkapi/wagtailpages/pagemodels/customblocks/__init__.py b/network-api/networkapi/wagtailpages/pagemodels/customblocks/__init__.py index 953b5bf4221..8d672a338cb 100644 --- a/network-api/networkapi/wagtailpages/pagemodels/customblocks/__init__.py +++ b/network-api/networkapi/wagtailpages/pagemodels/customblocks/__init__.py @@ -4,6 +4,7 @@ from .advanced_table_block import AdvancedTableBlock from .airtable_block import AirTableBlock from .annotated_image_block import AnnotatedImageBlock +from .app_install_download_button_block import AppInstallDownloadButtonBlock from .article_teaser_block import ArticleTeaserBlock from .articles import ( ArticleDoubleImageBlock, diff --git a/network-api/networkapi/wagtailpages/pagemodels/customblocks/app_install_download_button_block.py b/network-api/networkapi/wagtailpages/pagemodels/customblocks/app_install_download_button_block.py new file mode 100644 index 00000000000..4fea9baedff --- /dev/null +++ b/network-api/networkapi/wagtailpages/pagemodels/customblocks/app_install_download_button_block.py @@ -0,0 +1,12 @@ +from wagtail import blocks +from wagtail.images.blocks import ImageChooserBlock + +from networkapi.wagtailpages.pagemodels.customblocks.link_block import LinkBlock + + +class AppInstallDownloadButtonBlock(LinkBlock): + icon = ImageChooserBlock(required=False, help_text="For best results, please use black or white icons.") + icon_alt_text = blocks.CharBlock(required=False, help_text="Image description (for screen readers).") + + class Meta: + template = "wagtailpages/blocks/app_install_download_button_block.html" diff --git a/network-api/networkapi/wagtailpages/templates/wagtailpages/app_install_page.html b/network-api/networkapi/wagtailpages/templates/wagtailpages/app_install_page.html new file mode 100644 index 00000000000..a2c4bbacc8c --- /dev/null +++ b/network-api/networkapi/wagtailpages/templates/wagtailpages/app_install_page.html @@ -0,0 +1,22 @@ +{% extends "./campaign_page.html" %} + +{% block subcontent %} + {% include "./fragments/app_install_hero.html" %} + {{ block.super }} +{% endblock subcontent %} + +{% block html_content_desktop %} + {% include "./fragments/campaign_main_body.html" with page=page class="tw-block" %} +{% endblock html_content_desktop %} + +{% block campaign_page_header %} +{% endblock campaign_page_header %} + +{% block campaign_page_menu %} +{% endblock campaign_page_menu %} + +{% block html_content_mobile %} +{% endblock html_content_mobile %} + +{% block cta_sticky_button %} +{% endblock cta_sticky_button %} diff --git a/network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/app_install_download_button_block.html b/network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/app_install_download_button_block.html new file mode 100644 index 00000000000..5379523e8e6 --- /dev/null +++ b/network-api/networkapi/wagtailpages/templates/wagtailpages/blocks/app_install_download_button_block.html @@ -0,0 +1,10 @@ + +{% load wagtailcore_tags wagtailimages_tags %} + + + {% if value.icon %} + {% image value.icon original as btn_icon %} + + {% endif %} + {{ value.label }} + diff --git a/network-api/networkapi/wagtailpages/templates/wagtailpages/campaign_page.html b/network-api/networkapi/wagtailpages/templates/wagtailpages/campaign_page.html index f49b065becb..9dd442b2a59 100644 --- a/network-api/networkapi/wagtailpages/templates/wagtailpages/campaign_page.html +++ b/network-api/networkapi/wagtailpages/templates/wagtailpages/campaign_page.html @@ -58,16 +58,18 @@
+ {{ page.hero_subheading }} +
+ {% if page.download_buttons %} +