Merge `feature/donate-help-page` into `main` (#11359)

* DonateHelpPage model, factory, and tests

* formatting

* html formatting

* template for notice section is done

* added "show_notice" flag

* Added newline at the end of help_page_notice.html

* feedback from PR

* formatting

* saving progress, page is now working with body but need to update scss still

* feedback from PR

* added height/width attributes to image for linter

* feedback from PR

* updated scss, factory, and template

* backend work done

* added new notice block instead so we can update template individually

* backend done, unless we want to make image optional

* updated help page to use new notice block instead of imagetextmini

* updated migrations

* linting

* formatting

* fixed typo

* updated to use StructBlockValidationError

* updated tests

* smal front end update

* linting notice-block.scss

* updated migrations, having trouble with NoticeBlockFactory

* block factories & tests, updating of factory file structure

* updated import

* updated some factory file paths to account for changes

* import formatting

* removed forgotten factory.py file

* first pass, have the form rendering with default styling

* formatting

* updated spacing

* updated linting file to ignore errors from FA code

* added donate and donate help page to visual regression tests

* removed donate pages from visual regression tests since they live on a different subdomain (donate.localhost)

* very first pass, borrowing existing file to get feedback from design

* fixed bug where submit button would not render for last two dropdown options

* fixed error where text box wouldnt show up for 2nd to last option

* feedback from pr (add comments, update env.default and other small changes)

* added newline at end of formassembly_body.html

* updated chevron in the select dropdown

* feedback from stakeholders (increased textarea height and implemented word wrapping on select element for chrome)

* fixed dropdown styling/wrap issue

* updated scss, ready for review

* Formatting of scss file

* updated app.json and continuous-integration.yml to include updated sp directives

* Feedback from PR (height to min-height)

* localized form and updated instructions

* updated formassembly JS

* formatting

* localized submit button value

* updated revision number

* feedback from PR (wrapping dropdown options in trans blocks)
This commit is contained in:
Daniel Miranda 2023-11-06 19:25:57 -08:00 коммит произвёл GitHub
Родитель 01ee5213cd
Коммит 87a3ac5085
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
32 изменённых файлов: 2308 добавлений и 89 удалений

3
.github/workflows/continous-integration.yml поставляемый
Просмотреть файл

@ -147,7 +147,8 @@ jobs:
XSS_PROTECTION: True
CSP_CONNECT_SRC: "*"
CSP_FONT_SRC: "'self' https://fonts.gstatic.com https://fonts.googleapis.com https://code.cdn.mozilla.net https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/fonts/ data:"
CSP_SCRIPT_SRC: "'self' 'unsafe-inline' https://www.google-analytics.com/analytics.js http://*.shpg.org/ https://comments.mozillafoundation.org/ https://airtable.com https://platform.twitter.com https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/gsap.min.js https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/ScrollTrigger.min.js https://*.googletagmanager.com https://*.fundraiseup.com https://mozillafoundation.tfaforms.net 'unsafe-eval'"
CSP_FRAME_SRC: "'self' https://www.google.com/recaptcha/"
CSP_SCRIPT_SRC: "'self' 'unsafe-inline' https://www.google-analytics.com/analytics.js http://*.shpg.org/ https://comments.mozillafoundation.org/ https://airtable.com https://platform.twitter.com https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/gsap.min.js https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/ScrollTrigger.min.js https://*.googletagmanager.com https://*.fundraiseup.com https://mozillafoundation.tfaforms.net https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ 'unsafe-eval'"
CSP_STYLE_SRC: "'self' 'unsafe-inline' https://code.cdn.mozilla.net https://fonts.googleapis.com https://platform.twitter.com https://mozillafoundation.tfaforms.net https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
steps:
- uses: actions/checkout@v3

Просмотреть файл

@ -27,11 +27,11 @@
"CSP_CONNECT_SRC": "*",
"CSP_DEFAULT_SRC": "'none'",
"CSP_FRAME_ANCESTORS": "'none'",
"CSP_FRAME_SRC": "'self' https://js.tito.io",
"CSP_FRAME_SRC": "'self' https://js.tito.io https://www.google.com/recaptcha/",
"CSP_FONT_SRC": "'self' https://fonts.gstatic.com https://fonts.googleapis.com https://code.cdn.mozilla.net https://static.fundraiseup.com/fonts/ https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/fonts/",
"CSP_IMG_SRC": "* data:",
"CSP_MEDIA_SRC": "'self' https://s3.amazonaws.com/mofo-assets/foundation/video/",
"CSP_SCRIPT_SRC": "'self' 'unsafe-inline' https://www.google-analytics.com/analytics.js http://*.shpg.org/ https://comments.mozillafoundation.org/ https://airtable.com https://platform.twitter.com https://cdn.syndication.twimg.com https://js.tito.io https://js-plugins.tito.io/gtm.js https://*.fundraiseup.com *.googletagmanager.com https://mozillafoundation.tfaforms.net 'unsafe-eval'",
"CSP_SCRIPT_SRC": "'self' 'unsafe-inline' https://www.google-analytics.com/analytics.js http://*.shpg.org/ https://comments.mozillafoundation.org/ https://airtable.com https://platform.twitter.com https://cdn.syndication.twimg.com https://js.tito.io https://js-plugins.tito.io/gtm.js https://*.fundraiseup.com *.googletagmanager.com https://mozillafoundation.tfaforms.net https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ 'unsafe-eval'",
"CSP_STYLE_SRC": "'self' 'unsafe-inline' https://code.cdn.mozilla.net https://fonts.googleapis.com https://platform.twitter.com https://js.tito.io https://mozillafoundation.tfaforms.net https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css",
"NPM_CONFIG_PRODUCTION": "true",
"REVIEW_APP": "True",

Просмотреть файл

@ -53,10 +53,10 @@ CSP_CONNECT_SRC=" * "
CSP_DEFAULT_SRC=" 'none' "
CSP_FONT_SRC=" 'self' data: https://fonts.gstatic.com https://fonts.googleapis.com https://code.cdn.mozilla.net https://static.fundraiseup.com/fonts/ https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/fonts/"
CSP_FRAME_ANCESTORS=" 'none' "
CSP_FRAME_SRC=" 'self' https://www.youtube.com https://comments.mozillafoundation.org/ https://airtable.com https://docs.google.com/ https://platform.twitter.com https://public.zenkit.com https://calendar.google.com https://www.youtube-nocookie.com https://form.typeform.com https://js.tito.io https://datawrapper.dwcdn.net"
CSP_FRAME_SRC=" 'self' https://www.youtube.com https://comments.mozillafoundation.org/ https://airtable.com https://docs.google.com/ https://platform.twitter.com https://public.zenkit.com https://calendar.google.com https://www.youtube-nocookie.com https://form.typeform.com https://js.tito.io https://datawrapper.dwcdn.net https://www.google.com/recaptcha/"
CSP_IMG_SRC=" * data: "
CSP_MEDIA_SRC=" 'self' data: https://s3.amazonaws.com/mofo-assets/foundation/video/ "
CSP_SCRIPT_SRC=" 'self' 'unsafe-inline' https://www.google-analytics.com/analytics.js http://*.shpg.org/ https://comments.mozillafoundation.org/ https://airtable.com https://platform.twitter.com https://cdn.syndication.twimg.com https://embed.typeform.com https://js.tito.io https://js-plugins.tito.io/gtm.js https://tagmanager.google.com *.googletagmanager.com https://*.fundraiseup.com https://mozillafoundation.tfaforms.net 'unsafe-eval'"
CSP_SCRIPT_SRC=" 'self' 'unsafe-inline' https://www.google-analytics.com/analytics.js http://*.shpg.org/ https://comments.mozillafoundation.org/ https://airtable.com https://platform.twitter.com https://cdn.syndication.twimg.com https://embed.typeform.com https://js.tito.io https://js-plugins.tito.io/gtm.js https://tagmanager.google.com *.googletagmanager.com https://*.fundraiseup.com https://mozillafoundation.tfaforms.net https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ 'unsafe-eval'"
CSP_STYLE_SRC=" 'self' 'unsafe-inline' https://code.cdn.mozilla.net https://fonts.googleapis.com https://platform.twitter.com https://js.tito.io https://tagmanager.google.com https://mozillafoundation.tfaforms.net https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
CSP_INCLUDE_NONCE_IN=script-src

Просмотреть файл

@ -0,0 +1,12 @@
from . import help_page, landing_page
def generate(seed):
# these are not, and should not be, alphabetically ordered.
landing_page.generate(seed)
help_page.generate(seed)
__all__ = [
"generate",
]

Просмотреть файл

@ -0,0 +1,2 @@
# flake8: noqa
from .notice_block import NoticeBlockFactory

Просмотреть файл

@ -0,0 +1,20 @@
import wagtail_factories
from factory import Faker, LazyAttribute, SubFactory
from wagtail.rich_text import RichText
from networkapi.donate.pagemodels.customblocks.notice_block import NoticeBlock
description_faker = Faker("paragraphs", nb=2)
class NoticeBlockFactory(wagtail_factories.StructBlockFactory):
class Meta:
model = NoticeBlock
exclude = ("description_text",)
image = SubFactory(wagtail_factories.ImageChooserBlockFactory)
image_alt_text = Faker("sentence", nb_words=4)
text = LazyAttribute(lambda o: RichText("".join([f"<p>{p}</p>" for p in o.description_text])))
# Lazy Values
description_text = description_faker

Просмотреть файл

@ -0,0 +1,29 @@
import wagtail_factories
from factory import Faker, SubFactory
from wagtail_factories import PageFactory
from networkapi.donate.factory.customblocks.notice_block import NoticeBlockFactory
from networkapi.donate.models import DonateHelpPage, DonateLandingPage
from networkapi.utility.faker import StreamfieldProvider
from networkapi.utility.faker.helpers import reseed
Faker.add_provider(StreamfieldProvider)
streamfield_fields = ["paragraph", "spacer", "image", "image_text", "quote"]
class DonateHelpPageFactory(PageFactory):
class Meta:
model = DonateHelpPage
title = Faker("sentence", nb_words=2)
body = Faker("streamfield", fields=streamfield_fields)
notice = wagtail_factories.StreamFieldFactory({"notice": SubFactory(NoticeBlockFactory)})
def generate(seed):
reseed(seed)
print("Generating a Help page")
home_page = DonateLandingPage.objects.get(title="Donate Now")
DonateHelpPageFactory(parent=home_page, title="Donate Help", slug="help", notice__0="notice")

Просмотреть файл

@ -5,9 +5,17 @@ from wagtail.models import Site as WagtailSite
from wagtail_factories import PageFactory
from networkapi.donate.models import DonateLandingPage
from networkapi.utility.faker import StreamfieldProvider
from networkapi.utility.faker.helpers import reseed
from networkapi.wagtailpages.factory.image_factory import ImageFactory
description_faker = Faker("paragraphs", nb=2)
Faker.add_provider(StreamfieldProvider)
streamfield_fields = ["paragraph", "spacer", "image", "image_text", "quote"]
class DonateLandingPageFactory(PageFactory):
class Meta:
@ -31,8 +39,6 @@ def generate(seed):
home_page = DonateLandingPageFactory.create(parent=site_root, title="Donate Now", slug=None)
reseed(seed)
print("Creating Donate Site record in Wagtail")
tds = settings.TARGET_DOMAINS
if tds and len(tds) > 2:

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,41 @@
# Generated by Django 3.2.21 on 2023-10-17 06:37
import wagtail.blocks
import wagtail.fields
import wagtail.images.blocks
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("donate", "0002_donatehelppage"),
]
operations = [
migrations.AddField(
model_name="donatehelppage",
name="notice",
field=wagtail.fields.StreamField(
[
(
"notice",
wagtail.blocks.StructBlock(
[
("image", wagtail.images.blocks.ImageChooserBlock(required=False)),
(
"image_alt_text",
wagtail.blocks.CharBlock(
help_text="Image description (for screen readers).", required=False
),
),
("text", wagtail.blocks.RichTextBlock(features=["bold", "italic", "link"])),
]
),
)
],
blank=True,
help_text="Optional notice that will render at the top of the page.",
use_json_field=True,
),
),
]

Просмотреть файл

@ -1,46 +1,4 @@
from django.db import models
from wagtail.admin.panels import FieldPanel
from wagtail.fields import RichTextField
from wagtail.models import Page
from wagtail_localize.fields import SynchronizedField, TranslatableField
from networkapi.wagtailpages.models import FoundationMetadataPageMixin
class BaseDonationPage(FoundationMetadataPageMixin, Page):
class Meta:
abstract = True
class DonateLandingPage(BaseDonationPage):
template = "donate/pages/landing_page.html"
# Only allow creating landing pages at the root level
parent_page_types = ["wagtailcore.Page"]
subpage_types: list = []
featured_image = models.ForeignKey(
"wagtailimages.Image",
models.PROTECT,
related_name="+",
)
intro = RichTextField()
content_panels = Page.content_panels + [
FieldPanel("featured_image"),
FieldPanel("intro"),
]
translatable_fields = [
# Promote tab fields
SynchronizedField("slug"),
TranslatableField("seo_title"),
SynchronizedField("show_in_menus"),
TranslatableField("search_description"),
SynchronizedField("search_image"),
# Content tab fields
TranslatableField("title"),
SynchronizedField("featured_image"),
TranslatableField("intro"),
]
# flake8: noqa
from .pagemodels.base_page import BaseDonationPage
from .pagemodels.help_page import DonateHelpPage
from .pagemodels.landing_page import DonateLandingPage

Просмотреть файл

Просмотреть файл

@ -0,0 +1,8 @@
from wagtail.models import Page
from networkapi.wagtailpages.models import FoundationMetadataPageMixin
class BaseDonationPage(FoundationMetadataPageMixin, Page):
class Meta:
abstract = True

Просмотреть файл

@ -0,0 +1,31 @@
from django.forms.utils import ErrorList
from wagtail.blocks.struct_block import StructBlockValidationError
from wagtail.core import blocks
from wagtail.images.blocks import ImageChooserBlock
from networkapi.wagtailpages.pagemodels.customblocks.base_rich_text_options import (
base_rich_text_options,
)
class NoticeBlock(blocks.StructBlock):
image = ImageChooserBlock(required=False)
image_alt_text = blocks.CharBlock(required=False, help_text="Image description (for screen readers).")
text = blocks.RichTextBlock(features=base_rich_text_options)
class Meta:
icon = "doc-full"
template = "donate/blocks/notice_block.html"
def clean(self, value):
cleaned_data = super().clean(value)
errors = {}
if cleaned_data["image"] and not cleaned_data["image_alt_text"]:
errors["image"] = ErrorList(["Image must include alt text."])
if cleaned_data["image_alt_text"] and not cleaned_data["image"]:
errors["image_alt_text"] = ErrorList(["Alt text must have an associated image."])
if errors:
raise StructBlockValidationError(errors)
return cleaned_data

Просмотреть файл

@ -0,0 +1,45 @@
from wagtail.admin.panels import FieldPanel
from wagtail.fields import StreamField
from wagtail.models import Page
from wagtail_localize.fields import SynchronizedField, TranslatableField
from networkapi.donate.models import BaseDonationPage
from networkapi.donate.pagemodels.customblocks.notice_block import NoticeBlock
from networkapi.wagtailpages.pagemodels.customblocks.base_fields import base_fields
class DonateHelpPage(BaseDonationPage):
template = "donate/pages/help_page.html"
parent_page_types = ["DonateLandingPage"]
subpage_types: list = []
max_count = 1
notice = StreamField(
[("notice", NoticeBlock())],
help_text="Optional notice that will render at the top of the page.",
blank=True,
max_num=1,
use_json_field=True,
)
body = StreamField(base_fields, blank=True, use_json_field=True)
content_panels = Page.content_panels + [
FieldPanel("notice"),
FieldPanel("body"),
]
translatable_fields = [
# Promote tab fields
SynchronizedField("slug"),
TranslatableField("seo_title"),
SynchronizedField("show_in_menus"),
TranslatableField("search_description"),
SynchronizedField("search_image"),
# Content tab fields
TranslatableField("notice"),
TranslatableField("body"),
]

Просмотреть файл

@ -0,0 +1,41 @@
from django.db import models
from wagtail.admin.panels import FieldPanel
from wagtail.fields import RichTextField
from wagtail.models import Page
from wagtail_localize.fields import SynchronizedField, TranslatableField
from networkapi.donate.models import BaseDonationPage
class DonateLandingPage(BaseDonationPage):
template = "donate/pages/landing_page.html"
# Only allow creating landing pages at the root level
parent_page_types: list = ["wagtailcore.Page"]
subpage_types: list = ["DonateHelpPage"]
featured_image = models.ForeignKey(
"wagtailimages.Image",
models.PROTECT,
related_name="+",
)
intro = RichTextField()
content_panels = Page.content_panels + [
FieldPanel("featured_image"),
FieldPanel("intro"),
]
translatable_fields = [
# Promote tab fields
SynchronizedField("slug"),
TranslatableField("seo_title"),
SynchronizedField("show_in_menus"),
TranslatableField("search_description"),
SynchronizedField("search_image"),
# Content tab fields
TranslatableField("title"),
SynchronizedField("featured_image"),
TranslatableField("intro"),
]

Просмотреть файл

Просмотреть файл

@ -0,0 +1,98 @@
from django.test import TestCase
from wagtail import rich_text
from wagtail.blocks.struct_block import StructBlockValidationError
from wagtail.images.tests.utils import Image, get_test_image_file
from networkapi.donate.factory.customblocks.notice_block import NoticeBlockFactory
from networkapi.donate.pagemodels.customblocks.notice_block import NoticeBlock
class NoticeBlockTest(TestCase):
def setUp(self):
self.notice_block = NoticeBlock()
def test_notice_block_factory(self):
"""
Testing that the factory can successfully create a valid NoticeBlock.
"""
notice_block_factory_default_values = NoticeBlockFactory()
is_valid = self.notice_block.clean(notice_block_factory_default_values)
self.assertTrue(is_valid)
def test_valid_notice_block(self):
"""
Testing that a notice block with all fields is valid.
"""
value = {
"image": Image.objects.create(title="Test Image", file=get_test_image_file()),
"image_alt_text": "Alt text",
"text": rich_text.RichText("<p>Some content</p>"),
}
is_valid = self.notice_block.clean(value)
self.assertTrue(is_valid)
def test_image_without_alt_text_raises_error(self):
"""
Testing that a notice block with an image but no alt text is invalid.
"""
value = {
"image": Image.objects.create(title="Test Image", file=get_test_image_file()),
"image_alt_text": "",
"text": rich_text.RichText("<p>Some content</p>"),
}
with self.assertRaises(StructBlockValidationError) as ValidationError:
self.notice_block.clean(value)
exception = ValidationError.exception
self.assertIn("image", exception.params)
self.assertEqual(exception.params["image"], ["Image must include alt text."])
def test_alt_text_without_image_raises_error(self):
"""
Testing that a notice block with alt text but no image is invalid.
"""
value = {
"image": None,
"image_alt_text": "Alt text",
"text": rich_text.RichText("<p>Some content</p>"),
}
with self.assertRaises(StructBlockValidationError) as ValidationError:
self.notice_block.clean(value)
exception = ValidationError.exception
self.assertIn("image_alt_text", exception.params)
self.assertEqual(exception.params["image_alt_text"], ["Alt text must have an associated image."])
def test_notice_text_field_is_required(self):
"""
Testing that a notice block with no body text is invalid.
"""
value = {
"image": Image.objects.create(title="Test Image", file=get_test_image_file()),
"image_alt_text": "Alt text",
"text": rich_text.RichText(""),
}
with self.assertRaises(StructBlockValidationError) as ValidationError:
self.notice_block.clean(value)
exception = ValidationError.exception
self.assertIn("text", exception.params)
self.assertEqual(exception.params["text"], ["This field is required."])
def test_valid_block_without_image_and_alt_text(self):
"""
Testing that a notice block with only text is valid.
"""
value = {
"image": None,
"image_alt_text": "",
"text": rich_text.RichText("<p>Some content</p>"),
}
is_valid = self.notice_block.clean(value)
self.assertTrue(is_valid)

Просмотреть файл

@ -0,0 +1,73 @@
from http import HTTPStatus
from networkapi.donate import models as pagemodels
from networkapi.donate.factory import help_page as help_page_factories
from networkapi.wagtailpages.tests import base as test_base
class FactoriesTest(test_base.WagtailpagesTestCase):
def test_page_factory(self):
"""
Testing the factory can successfully create a DonateHelpPage.
"""
help_page_factories.DonateHelpPageFactory()
class DonateHelpPageTest(test_base.WagtailpagesTestCase):
@classmethod
def setUpTestData(cls):
super().setUpTestData()
cls.donate_landing_page = help_page_factories.DonateHelpPageFactory(
parent=cls.homepage,
)
cls.donate_help_page = help_page_factories.DonateHelpPageFactory(
parent=cls.donate_landing_page,
notice__0="notice",
)
def test_parent_page_types(self):
"""
Testing that the DonateHelpPage model can only be created as a child of a landing page.
"""
self.assertAllowedParentPageTypes(
child_model=pagemodels.DonateHelpPage,
parent_models={pagemodels.DonateLandingPage},
)
def test_subpage_types(self):
"""
Testing the DonateHelpPage's allowed subpage types.
"""
self.assertAllowedSubpageTypes(
parent_model=pagemodels.DonateHelpPage,
child_models={},
)
def test_page_success(self):
"""
Testing that visiting a DonateHelpPage's URL returns a successful HTTP status.
"""
url = self.donate_help_page.get_url()
response = self.client.get(url)
self.assertEqual(response.status_code, HTTPStatus.OK)
def test_template(self):
"""
Testing that visiting a DonateHelpPage's URL renders the correct templates.
"""
url = self.donate_help_page.get_url()
response = self.client.get(url)
self.assertTemplateUsed(
response=response,
template_name="donate/pages/help_page.html",
)
def test_help_page_notice_field(self):
"""
Asserts that a 'notice' block was created in the 'notice' field by the factory.
"""
self.assertEqual(self.donate_help_page.notice[0].block_type, "notice")

Просмотреть файл

@ -2,8 +2,8 @@ from http import HTTPStatus
from wagtail.models import Page as WagtailPage
from networkapi.donate import factory as donate_factories
from networkapi.donate import models as pagemodels
from networkapi.donate.factory import landing_page as landing_page_factories
from networkapi.wagtailpages.tests import base as test_base
@ -12,14 +12,14 @@ class FactoriesTest(test_base.WagtailpagesTestCase):
"""
Testing the factory can successfully create a DonateLandingPage.
"""
donate_factories.DonateLandingPageFactory()
landing_page_factories.DonateLandingPageFactory()
class DonateLandingPageTest(test_base.WagtailpagesTestCase):
@classmethod
def setUpTestData(cls):
super().setUpTestData()
cls.donate_landing_page = donate_factories.DonateLandingPageFactory(
cls.donate_landing_page = landing_page_factories.DonateLandingPageFactory(
parent=cls.homepage,
)
@ -38,7 +38,7 @@ class DonateLandingPageTest(test_base.WagtailpagesTestCase):
"""
self.assertAllowedSubpageTypes(
parent_model=pagemodels.DonateLandingPage,
child_models={},
child_models={pagemodels.DonateHelpPage},
)
def test_page_success(self):

Просмотреть файл

@ -0,0 +1,14 @@
{% load l10n wagtailcore_tags wagtailimages_tags %}
<div class="tw-py-4 tw-px-0 medium:tw-p-8 tw-my-24 tw-w-full tw-flex tw-flex-col large:tw-flex-row tw-items-start large:tw-items-center tw-border-t tw-border-b tw-border-black">
{% if value.image %}
<div class="tw-flex-shrink-0 tw-grow-0 tw-basis-24 tw-mr-4 medium:tw-mr-8">
{% image value.image fill-100x100-c100 format-jpeg as img %}
<img src="{{ img.url }}" alt="{{ value.image_alt_text }}" class="tw-w-full" width="{{ img.width|unlocalize }}" height="{{ img.height|unlocalize }}">
</div>
{% endif %}
<div class="notice-block-text">
{{ value.text|richtext }}
</div>
</div>

Просмотреть файл

@ -0,0 +1,162 @@
{% load i18n %}
{% comment %}
*** IMPORTANT ***
The code below has been copied directly over from FormAssembly.
Please follow the steps below every time after you paste a new version of FormAssembly code.
1. Replace everything starting from <!-- FORM: BODY SECTION -->
2. Run `inv format-html` in terminal
3. Add nonce="{{ csp_nonce }}" to all script tags in this file
4. Get localization working again.
- Localize "title" attribute and label text for all fields using {% trans %} or {% blocktrans %}.
- If applicable, localize any other text on the form. For example, text within htmlContent divs.
- Localize "value" attribute for <input type="submit" ...>
- Go to formassembly_head.html and make sure everything has been updated according to the instructions.
5. Update the revision note on the next line. Revision number can be found on https://mozillafoundation.tfaforms.net/versions/index/12
The code snippet below is based on FormAssembly form revision #43
{% endcomment %}
<!-- FORM: BODY SECTION -->
<div class="wFormContainer" style="max-width: 100%; width:auto;">
<div class="wFormHeader"></div>
<div class=""><div class="wForm" id="12-WRPR" dir="ltr">
<div class="codesection" id="code-12"><script nonce="{{ request.csp_nonce }}">
// From Mel A at Thunderbird. 06.09.2023. Edited by Mia to change adding en- locales to map and defaulting to 'Other'. Approved by Mel.
// localeMap updated by Daniel at Mozilla 10.31.2023, to reflect languages that are currently supported on the foundation site.
window.addEventListener('DOMContentLoaded', function () {
// Retrieve the Language alias (locale field) on the form.
const varLocale = document.getElementById('tfa_72');
// Exit if we can't find the locale selection dropdown
if (!varLocale) {
return;
}
// Retrieve the url, and attempt to get the first parameter (locale)
const url = new URL(window.location);
const locale = url.pathname.split('/')[1] || null;
// If locale does not exist in the url, then there's nothing more to do.
if (!locale) {
return;
}
// Match up locale codes with the locale dropdown entries
const localeMap = {
'nl': 'tfa_221',
'fy-NL': 'tfa_221',
'en': 'tfa_222',
'fr': 'tfa_223',
'de': 'tfa_224',
'pl': 'tfa_228',
'pt-BR': 'tfa_229',
'es': 'tfa_231',
}
// Assign the locale, or default to 'Other' if the locale isn't supported.
varLocale.value = localeMap[locale] || 'tfa_227';
});
</script></div>
<form method="post" action="https://mozillafoundation.tfaforms.net/api_v2/workflow/processor" class=" labelsAbove" id="12" role="form" enctype="multipart/form-data" style="padding:0;">
<div class="oneField field-container-D labelsAbove " id="tfa_95-D">
<label id="tfa_95-L" class="label preField" for="tfa_95">{% trans "I need" %}</label><br><div class="inputWrapper"><select aria-required="true" id="tfa_95" name="tfa_95" title="{% trans "I need" %}" class="required"><option value="">{% trans "Please select..." %}</option>
<option value="tfa_194" id="tfa_194" data-conditionals="#tfa_212,#submit_button,#tfa_214,#tfa_163" class="">{% trans "Help with the donation form" %}</option>
<option value="tfa_195" id="tfa_195" data-conditionals="#tfa_212,#submit_button,#tfa_163,#tfa_234" class="">{% trans "To change or cancel my monthly recurring donation" %}</option>
<option value="tfa_193" id="tfa_193" data-conditionals="#tfa_212,#submit_button,#tfa_163" class="">{% trans "To update my email address or contact info" %}</option>
<option value="tfa_192" id="tfa_192" data-conditionals="#tfa_212,#submit_button,#tfa_217,#tfa_163" class="">{% trans "Help donating by bank transfer (SEPA/IBAN)" %}</option>
<option value="tfa_196" id="tfa_196" data-conditionals="#tfa_212,#submit_button,#tfa_163" class="">{% trans "Help donating with another currency or payment method" %}</option>
<option value="tfa_197" id="tfa_197" data-conditionals="#tfa_212,#submit_button,#tfa_214,#tfa_163" class="">{% trans "Help with an unauthorized or fraudulent donation" %}</option>
<option value="tfa_190" id="tfa_190" data-conditionals="#tfa_212,#submit_button,#tfa_163" class="">{% trans "A copy of my donation receipt" %}</option>
<option value="tfa_191" id="tfa_191" data-conditionals="#tfa_212,#submit_button,#tfa_163" class="">{% trans "A year-end donation summary" %}</option>
<option value="tfa_198" id="tfa_198" data-conditionals="#tfa_212,#submit_button,#tfa_163" class="">{% trans "My donation refunded" %}</option>
<option value="tfa_199" id="tfa_199" data-conditionals="#tfa_212" class="">{% trans "To submit feedback" %}</option>
<option value="tfa_200" id="tfa_200" data-conditionals="#tfa_212,#tfa_214,#tfa_163" class="">{% trans "Help with something else" %}</option></select></div>
</div>
<div id="tfa_217" class="section group" data-condition="`#tfa_192`"><div class="htmlSection" id="tfa_216"><div class="htmlContent" id="tfa_216-HTML"><span style="font-size:13px;color:#000000;font-weight:normal;text-decoration:none;font-family:'Arial';font-style:normal;text-decoration-skip-ink:none;">
{% blocktrans %}
We truly appreciate your generous support and are happy to now offer an
easier way for you to give through online bank transfer. We can accept
donations via direct debit in Euros through Single European Payment Area
(SEPA) transfer.
{% endblocktrans %}
</span><br><br><div><b><a target="_blank" href="https://foundation.mozilla.org/?form=donate&amp;utm_medium=web&amp;utm_source=faq-page&amp;utm_campaign=23-Donor-Care&amp;utm_term=en"><u>{% trans "Make your donation online now" %}<br><br></u></a></b><i>{% trans "Still have questions? Contact us by submitting a case." %}</i><br></div></div></div></div>
<div id="tfa_234" class="section group" data-condition="`#tfa_195`"><div class="htmlSection" id="tfa_235"><div class="htmlContent" id="tfa_235-HTML"><span style="font-size:13px;color:#000000;font-weight:normal;text-decoration:none;font-family:'Arial';font-style:normal;text-decoration-skip-ink:none;">
{% blocktrans %}
Access your donation account settings using the '<b>Manage My Donation</b>'
button on your recent donation confirmation email. There you can
change the amount, frequency, payment method and charge date. You can
also cancel your recurring donation plan.
{% endblocktrans %}
</span><br><br><i>{% trans "Still have questions? Contact us by submitting a case." %}</i></div></div></div>
<div class="oneField field-container-D labelsAbove " id="tfa_163-D">
<label id="tfa_163-L" class="label preField " for="tfa_163">{% trans "Any other details that might help" %}</label><br><div class="inputWrapper"><textarea id="tfa_163" name="tfa_163" data-condition="`#tfa_190` OR `#tfa_191` OR `#tfa_192` OR `#tfa_193` OR `#tfa_194` OR `#tfa_195` OR `#tfa_196` OR `#tfa_197` OR `#tfa_198` OR `#tfa_199` OR `#tfa_200`" title="{% trans "Any other details that might help" %}" class=""></textarea></div>
</div>
<div class="oneField field-container-D hintsBelow " id="tfa_214-D">
<label id="tfa_214-L" class="label preField " for="tfa_214">{% trans "Add a screenshot to help us with your request (optional)" %}</label><br><div class="inputWrapper">
<input type="file" id="tfa_214" name="tfa_214" size="" data-condition="`#tfa_194` OR `#tfa_197` OR `#tfa_200`" title="{% trans "Add a screenshot to help us with your request (optional)" %}" class=""><span class="field-hint-inactive" id="tfa_214-H"><span id="tfa_214-HH" class="hint">{% trans "JPG, PNG and BMP files only" %}</span></span>
</div>
</div>
<div id="tfa_212" class="section group" data-condition="`#tfa_190` OR `#tfa_191` OR `#tfa_192` OR `#tfa_193` OR `#tfa_194` OR `#tfa_195` OR `#tfa_196` OR `#tfa_197` OR `#tfa_198` OR `#tfa_199` OR `#tfa_200`"><div id="tfa_213" class="section inline group">
<div class="oneField field-container-D " id="tfa_1-D">
<label id="tfa_1-L" class="label preField reqMark" for="tfa_1">{% trans "Name" %}</label><br><div class="inputWrapper"><input aria-required="true" type="text" id="tfa_1" name="tfa_1" value="" title="{% trans "Name" %}" class="required"></div>
</div>
<div class="oneField field-container-D " id="tfa_10-D">
<label id="tfa_10-L" class="label preField reqMark" for="tfa_10">{% trans "Email" %}</label><br><div class="inputWrapper"><input aria-required="true" type="text" id="tfa_10" name="tfa_10" value="" title="{% trans "Email" %}" class="validate-email required"></div>
</div>
<div class="htmlSection" id="tfa_182"><div class="htmlContent" id="tfa_182-HTML">{% blocktrans with link="https://www.mozilla.org/privacy/websites/" %}Mozilla will only use your submitted information for purposes of communicating with you about your request. See our <a href="{{ link }}" target="_blank">privacy policy</a> for further information.{% endblocktrans %}
</div></div>
</div></div>
<div class="oneField field-container-D labelsLeftAligned wf-acl-hidden" id="tfa_72-D">
<label id="tfa_72-L" class="label preField " for="tfa_72">{% trans "Language" %}</label><div class="inputWrapper"><select id="tfa_72" name="tfa_72" title="{% trans "Language" %}" class=""><option value="">{% trans "Please select..." %}</option>
<option value="tfa_221" id="tfa_221" class="">Dutch</option>
<option value="tfa_222" id="tfa_222" class="">English</option>
<option value="tfa_223" id="tfa_223" class="">French</option>
<option value="tfa_224" id="tfa_224" class="">German</option>
<option value="tfa_227" id="tfa_227" class="">Other</option>
<option value="tfa_228" id="tfa_228" class="">Polish</option>
<option value="tfa_229" id="tfa_229" class="">Portuguese</option>
<option value="tfa_231" id="tfa_231" class="">Spanish</option></select></div>
</div>
<div class="actions" id="12-A" data-contentid="submit_button">
<div id="google-captcha" style="display: none">
<br><div class="captcha">
<div class="oneField">
<div class="g-recaptcha" id="g-recaptcha-render-div"></div>
<div class="g-captcha-error"></div>
<br>
</div>
<div class="captchaHelp">{% trans "reCAPTCHA helps prevent automated form spam." %}<br>
</div>
<div id="disabled-explanation" class="captchaHelp" style="display: none">{% trans "The submit button will be disabled until you complete the CAPTCHA." %}</div>
</div>
</div>
<input type="submit" data-label="Submit" class="primaryAction" id="submit_button" value="{% trans "Submit" %}" data-condition="`#tfa_190` OR `#tfa_191` OR `#tfa_192` OR `#tfa_193` OR `#tfa_194` OR `#tfa_195` OR `#tfa_196` OR `#tfa_197` OR `#tfa_198` OR `#tfa_199` OR `#tfa_200`" data-conditional-mode="hidden">
</div>
<div style="clear:both"></div>
<input type="hidden" value="12" name="tfa_dbFormId" id="tfa_dbFormId"><input type="hidden" value="" name="tfa_dbResponseId" id="tfa_dbResponseId"><input type="hidden" value="248931fbbdeec7bc8eff2364638bb781" name="tfa_dbControl" id="tfa_dbControl"><input type="hidden" value="" name="tfa_dbWorkflowSessionUuid" id="tfa_dbWorkflowSessionUuid"><input type="hidden" value="40" name="tfa_dbVersionId" id="tfa_dbVersionId"><input type="hidden" value="" name="tfa_switchedoff" id="tfa_switchedoff">
</form>
</div></div><div class="wFormFooter"><p class="supportInfo"><br></p></div>
<p class="supportInfo" >
</p>
</div>
<script
nonce="{{ request.csp_nonce }}"
id="open-telemetry-script"
type="text/javascript"
src="https://mozillafoundation.tfaforms.net/dist/open-telemetry/open-telemetry.3e6c1bedaa7fb4452dd0.js"
data-customer-id="170610"
data-exporter-url="https://us-east-1-otel.formassembly.com/v1/traces"
data-exporter-console="0"
></script>
<script src="https://mozillafoundation.tfaforms.net/api_v2/sst/copy-and-paste" nonce="{{ request.csp_nonce }}"></script>

Просмотреть файл

@ -0,0 +1,224 @@
{% load i18n formassembly_helper %}
{% get_current_language as LANGUAGE_CODE %}
{% comment %}
*** IMPORTANT ***
The code below has been copied directly over from FormAssembly.
Please follow the steps below every time after you paste a new version of FormAssembly code.
1. Replace everything starting from <!-- FORM: HEAD SECTION -->
2. Run `inv format-html` in terminal
3. Add nonce="{{ csp_nonce }}" to all script tags in this file
4. Get localization working again.
- Update script file name https://mozillafoundation.tfaforms.net/wForms/3.11/js/localization-en_US.js?v=...
with {% fa_locale_code %}
e.g., https://mozillafoundation.tfaforms.net/wForms/3.11/js/localization-{% fa_locale_code %}.js?v=...
- Go to formassembly_body.html and make sure everything has been updated according to the instructions
5. Update the revision note on the next line. Revision number can be found on https://mozillafoundation.tfaforms.net/versions/index/12
The code snippet below is based on FormAssembly form revision #43
{% endcomment %}
<!-- FORM: HEAD SECTION -->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="referrer" content="no-referrer-when-downgrade">
<!-- THIS SCRIPT NEEDS TO BE LOADED FIRST BEFORE wforms.js -->
<script nonce="{{ request.csp_nonce }}" type="text/javascript" data-for="FA__DOMContentLoadedEventDispatch" src="https://mozillafoundation.tfaforms.net/js/FA__DOMContentLoadedEventDispatcher.js" defer></script>
<style>
.captcha {
padding-bottom: 1em !important;
}
.wForm .captcha .oneField {
margin: 0;
padding: 0;
}
</style>
<script type="text/javascript" nonce="{{ request.csp_nonce }}">
// initialize our variables
var captchaReady = 0;
var wFORMSReady = 0;
var isConditionalSubmitEnabled = false;
// when wForms is loaded call this
var wformsReadyCallback = function () {
// using this var to denote if wForms is loaded
wFORMSReady = 1;
isConditionalSubmitEnabled = document.getElementById('submit_button').hasAttribute('data-condition');
// call our recaptcha function which is dependent on both
// wForms and an async call to google
// note the meat of this function wont fire until both
// wFORMSReady = 1 and captchaReady = 1
onloadCallback();
}
var gCaptchaReadyCallback = function() {
// using this var to denote if captcha is loaded
captchaReady = 1;
isConditionalSubmitEnabled = document.getElementById('submit_button').hasAttribute('data-condition');
// call our recaptcha function which is dependent on both
// wForms and an async call to google
// note the meat of this function wont fire until both
// wFORMSReady = 1 and captchaReady = 1
onloadCallback();
};
// add event listener to fire when wForms is fully loaded
document.addEventListener("wFORMSLoaded", wformsReadyCallback);
var enableSubmitButton = function() {
var submitButton = document.getElementById('submit_button');
var explanation = document.getElementById('disabled-explanation');
var isConditionalSubmitConditionMet = wFORMS.behaviors.condition.isConditionalSubmitConditionMet;
if (
submitButton != null &&
(isConditionalSubmitEnabled && isConditionalSubmitConditionMet) ||
!isConditionalSubmitEnabled
)
{
submitButton.removeAttribute('disabled');
if (explanation != null) {
explanation.style.display = 'none';
}
}
};
var disableSubmitButton = function() {
var submitButton = document.getElementById('submit_button');
var explanation = document.getElementById('disabled-explanation');
if (submitButton != null) {
submitButton.disabled = true;
if (explanation != null) {
explanation.style.display = 'block';
}
}
};
// call this on both captcha async complete and wforms fully
// initialized since we can't be sure which will complete first
// and we need both done for this to function just check that they are
// done to fire the functionality
var onloadCallback = function () {
// if our captcha is ready (async call completed)
// and wFORMS is completely loaded then we are ready to add
// the captcha to the page
if (captchaReady && wFORMSReady) {
grecaptcha.enterprise.render('g-recaptcha-render-div', {
'sitekey': '6LfMg_EaAAAAAMhDNLMlgqDChzmtYHlx1yU2y7GI',
'theme': 'light',
'size': 'normal',
'callback': 'enableSubmitButton',
'expired-callback': 'disableSubmitButton'
})
var oldRecaptchaCheck = parseInt('1');
if (oldRecaptchaCheck === -1) {
var standardCaptcha = document.getElementById("tfa_captcha_text");
standardCaptcha = standardCaptcha.parentNode.parentNode.parentNode;
standardCaptcha.parentNode.removeChild(standardCaptcha);
}
if (!wFORMS.instances['paging']) {
document.getElementById("g-recaptcha-render-div").parentNode.parentNode.parentNode.style.display = "block";
//document.getElementById("g-recaptcha-render-div").parentNode.parentNode.parentNode.removeAttribute("hidden");
}
document.getElementById("g-recaptcha-render-div").getAttributeNode('id').value = 'tfa_captcha_text';
var captchaError = '';
if (captchaError == '1') {
var errMsgText = 'The CAPTCHA was not completed successfully.';
var errMsgDiv = document.createElement('div');
errMsgDiv.id = "tfa_captcha_text-E";
errMsgDiv.className = "err errMsg";
errMsgDiv.innerText = errMsgText;
var loc = document.querySelector('.g-captcha-error');
loc.insertBefore(errMsgDiv, loc.childNodes[0]);
/* See wFORMS.behaviors.paging.applyTo for origin of this code */
if (wFORMS.instances['paging']) {
var b = wFORMS.instances['paging'][0];
var pp = base2.DOM.Element.querySelector(document, wFORMS.behaviors.paging.CAPTCHA_ERROR);
if (pp) {
var lastPage = 1;
for (var i = 1; i < 100; i++) {
if (b.behavior.isLastPageIndex(i)) {
lastPage = i;
break;
}
}
b.jumpTo(lastPage);
}
}
}
}
}
</script>
<script src='https://www.google.com/recaptcha/enterprise.js?onload=gCaptchaReadyCallback&render=explicit&hl=en_US' nonce="{{ request.csp_nonce }}" async
defer></script>
<script type="text/javascript" nonce="{{ request.csp_nonce }}">
document.addEventListener("DOMContentLoaded", function() {
var warning = document.getElementById("javascript-warning");
if (warning != null) {
warning.parentNode.removeChild(warning);
}
var oldRecaptchaCheck = parseInt('1');
if (oldRecaptchaCheck !== -1) {
var explanation = document.getElementById('disabled-explanation');
var submitButton = document.getElementById('submit_button');
if (submitButton != null) {
submitButton.disabled = true;
if (explanation != null) {
explanation.style.display = 'block';
}
}
}
});
</script>
<script type="text/javascript" nonce="{{ request.csp_nonce }}">
document.addEventListener("FA__DOMContentLoaded", function(){
const FORM_TIME_START = Math.floor((new Date).getTime()/1000);
let formElement = document.getElementById("tfa_0");
if (null === formElement) {
formElement = document.getElementById("0");
}
let appendJsTimerElement = function(){
let formTimeDiff = Math.floor((new Date).getTime()/1000) - FORM_TIME_START;
let cumulatedTimeElement = document.getElementById("tfa_dbCumulatedTime");
if (null !== cumulatedTimeElement) {
let cumulatedTime = parseInt(cumulatedTimeElement.value);
if (null !== cumulatedTime && cumulatedTime > 0) {
formTimeDiff += cumulatedTime;
}
}
let jsTimeInput = document.createElement("input");
jsTimeInput.setAttribute("type", "hidden");
jsTimeInput.setAttribute("value", formTimeDiff.toString());
jsTimeInput.setAttribute("name", "tfa_dbElapsedJsTime");
jsTimeInput.setAttribute("id", "tfa_dbElapsedJsTime");
jsTimeInput.setAttribute("autocomplete", "off");
if (null !== formElement) {
formElement.appendChild(jsTimeInput);
}
};
if (null !== formElement) {
if(formElement.addEventListener){
formElement.addEventListener('submit', appendJsTimerElement, false);
} else if(formElement.attachEvent){
formElement.attachEvent('onsubmit', appendJsTimerElement);
}
}
});
</script>
<link href="https://mozillafoundation.tfaforms.net/dist/form-builder/5.0.0/wforms-layout.css?v=910ede8cddaa51d331c5781cd8fc809dbb1cdd98" rel="stylesheet" type="text/css" />
<link href="https://mozillafoundation.tfaforms.net/uploads/themes/theme-27.css" rel="stylesheet" type="text/css" />
<link href="https://mozillafoundation.tfaforms.net/dist/form-builder/5.0.0/wforms-jsonly.css?v=910ede8cddaa51d331c5781cd8fc809dbb1cdd98" rel="alternate stylesheet" title="This stylesheet activated by javascript" type="text/css" />
<script type="text/javascript" nonce="{{ request.csp_nonce }}" src="https://mozillafoundation.tfaforms.net/wForms/3.11/js/wforms.js?v=910ede8cddaa51d331c5781cd8fc809dbb1cdd98"></script>
<script type="text/javascript" nonce="{{ request.csp_nonce }}">
wFORMS.behaviors.prefill.skip = false;
</script>
<script type="text/javascript" nonce="{{ request.csp_nonce }}" src="https://mozillafoundation.tfaforms.net/wForms/3.11/js/localization-{% fa_locale_code %}.js?v=910ede8cddaa51d331c5781cd8fc809dbb1cdd98"></script>

Просмотреть файл

@ -0,0 +1,35 @@
{% extends "../pages/base.html" %}
{% load static i18n l10n wagtailcore_tags wagtailimages_tags %}
{% block body_id %}help{% endblock body_id %}
{% block extended_head %}
{% include "../fragments/formassembly_head.html" %}
{% endblock extended_head %}
{% block content %}
<div class="tw-container tw-py-10">
<div class="cms donate-help-page-content">
<h1 class="tw-h1-heading"> {{ page.title }} </h1>
{% if page.notice %}
{% for block in page.notice %}
{% include_block block %}
{% endfor %}
{% endif %}
<p>
{% blocktrans trimmed %}
If you need help with a <a href="https://foundation.mozilla.org/?form=donate&utm_medium=web&utm_source=faq-page&utm_campaign=23-Donor-Care" target="_blank">donation</a> to the Mozilla Foundation, please select the reason for your inquiry from the drop down and a donor care representative will get back to you as soon as possible.
{% endblocktrans %}
</p>
<div class="tw-border-t tw-border-b tw-py-10 tw-mt-28 tw-mb-10 tw-border-gray-20">
<p class="tw-h3-heading"> Contact Us </p>
{% include "../fragments/formassembly_body.html" %}
<link rel="stylesheet" href="{% static "_css/formassembly-override.compiled.css" %}">
</div>
{% for block in page.body %}
{% include_block block with parent_page=page %}
{% endfor %}
</div>
</div>
{% endblock content %}

Просмотреть файл

@ -17,7 +17,7 @@
"build:css": "run-p build:css:file:**",
"build:css:file:main": "sass source/sass/main.scss network-api/networkapi/temp/frontend/_css/main.compiled.css",
"build:css:file:bg": "sass source/sass/buyers-guide/bg-main.scss network-api/networkapi/temp/frontend/_css/buyers-guide.compiled.css",
"build:css:file:donate": "sass source/sass/donate.scss network-api/networkapi/temp/frontend/_css/donate.compiled.css",
"build:css:file:donate": "sass source/sass/donate/donate-main.scss network-api/networkapi/temp/frontend/_css/donate.compiled.css",
"build:css:file:formassembly": "sass source/sass/formassembly-override.scss network-api/networkapi/temp/frontend/_css/formassembly-override.compiled.css",
"docker:up": "docker-compose up",
"docker:down": "docker-compose down",

Просмотреть файл

@ -15,6 +15,7 @@ ignore="H017"
[tool.djlint.per-file-ignores]
"maintenance/maintenance.html" = "D004,H005,H006,H013,H014,H025,H026,H030,H031"
"network-api/networkapi/templates/donate/fragments/footer.html" = "T003"
"network-api/networkapi/templates/donate/fragments/formassembly_body.html" = "H020,H021,H026"
"network-api/networkapi/templates/donate/pages/base.html" = "T003"
"network-api/networkapi/templates/donate/pages/landing_page.html" = "H006, T003"
"network-api/networkapi/mozfest/templates/fragments/event_card.html" = "H006"

Двоичные данные
source/images/donate/megaphone.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.9 KiB

Просмотреть файл

@ -1,30 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
*,
::before,
::after {
box-sizing: border-box;
}
article,
aside,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section {
display: block;
}
img {
max-width: 100%;
}
#view-landing .intro .rich-text {
@apply medium:tw-body-large;
}

Просмотреть файл

@ -0,0 +1,11 @@
.notice-block-text {
.rich-text {
p {
margin-bottom: 0;
&:not(:first-child) {
margin-top: 0.25rem;
}
}
}
}

Просмотреть файл

@ -0,0 +1,53 @@
// mofo-bootstrap
@import "../mofo-bootstrap/mofo-bootstrap";
@tailwind base;
@tailwind components;
@tailwind utilities;
// Custom variables
@import "../variables";
// Misc
@import "../cms";
// Wagtail Stream Blocks
@import "./blocks/notice-block.scss";
@import "../wagtail/blocks/airtable";
@import "../wagtail/blocks/feature-quote";
@import "../wagtail/blocks/image-text-mini";
@import "../wagtail/blocks/iframe-block";
@import "../wagtail/blocks/link-button.scss";
@import "../wagtail/blocks/rich-text";
@import "../wagtail/blocks/profiles";
@import "../wagtail/blocks/video-block";
@import "../wagtail/blocks/article-blocks";
@import "../wagtail/blocks/image-feature";
@import "../wagtail/blocks";
*,
::before,
::after {
box-sizing: border-box;
}
article,
aside,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section {
display: block;
}
img {
max-width: 100%;
}
#view-landing .intro .rich-text {
@apply medium:tw-body-large;
}

Просмотреть файл

@ -72,6 +72,11 @@ $input-font-size: 1.25rem !important;
border-color: transparent;
text-decoration: none;
}
&:disabled {
background-color: $light-blue;
border-color: transparent;
text-decoration: none;
}
&:hover {
cursor: pointer;
@ -96,10 +101,14 @@ $input-font-size: 1.25rem !important;
font-family: $font-family-sans-serif;
width: 100%;
padding: 1rem 0.75rem;
height: auto !important;
height: auto;
font-size: $input-font-size;
}
input[type="text"].validate-email {
height: auto !important;
}
textarea:focus,
textarea.required:focus,
input[type="text"]:focus,
@ -152,3 +161,114 @@ $input-font-size: 1.25rem !important;
#tfa_494-D {
margin-top: 0;
}
// DonateHelpPage form specific overrides
.donate-help-page-content {
.wForm {
label {
font-family: $font-family-sans-serif;
color: $black !important;
font-size: 1.125rem;
margin-bottom: 0;
}
input[type="text"],
input[type="text"].validate-email,
textarea,
select {
border-radius: 0 !important;
border: 1px solid black !important;
}
input[type="file"] {
padding: 0 !important;
height: auto !important;
&::file-selector-button {
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out;
font-family: $font-family-sans-serif;
background: $light-blue;
width: auto;
padding: 0rem 1.5rem;
font-size: 1rem;
border: none;
height: 2.25rem;
&:hover {
background: $blue;
cursor: pointer;
}
}
}
textarea {
min-height: 10em !important;
}
select {
appearance: none;
background: url("../_images/glyphs/down-chevron.svg") no-repeat 99% center;
padding-right: 30px !important;
white-space: normal;
text-overflow: ellipsis;
option {
@media (max-width: 576px) {
font-size: 0.75rem;
}
}
}
.oneField {
margin-top: 2rem;
}
.htmlSection {
padding: 0;
font-size: 0.75rem;
width: 100%;
span {
color: $black !important;
font-family: $font-family-sans-serif;
}
}
.htmlContent {
font-family: $font-family-sans-serif;
color: $black !important;
a {
color: $dark-blue;
}
}
.inline {
display: inline-flex;
flex-wrap: wrap;
justify-content: space-between;
.oneField {
width: 48.5%;
@media (max-width: 768px) {
width: 100%;
}
}
}
.captcha {
.oneField {
margin: 0;
}
.captchaHelp {
display: inline-flex !important;
padding: 0;
margin-top: 0.25rem;
color: $black;
}
}
.actions .primaryAction#submit_button {
width: auto !important;
}
}
}

Просмотреть файл

@ -69,6 +69,13 @@
}
}
.donate-help-page-content {
.streamfield-content {
@extend .px-0;
@extend .col-12;
}
}
.mozfest-content {
&.two-col {
@extend .p-0;