From 2b3d3a374d03bce9641f991e76b5e5840df4c157 Mon Sep 17 00:00:00 2001 From: luminaryFlowers <71102109+luminaryFlowers@users.noreply.github.com> Date: Tue, 13 Aug 2024 11:04:27 -0700 Subject: [PATCH] our work page => projects adjusted accordingly with the new fields that have filter options from the our work page => only thing that really remains for this page is mapbox styling but that's done via mapbox's settings if i'm not mistaken; the style in the MapboxScript component will need to be changed to some mapbox style --- ..._type_description_partnertype_type_icon.py | 26 ++ app/core/models.py | 16 +- .../individual_impact_area_page.html | 20 +- app/our_work/__init__.py | 0 app/our_work/admin.py | 3 + app/our_work/apps.py | 6 + app/our_work/migrations/0001_initial.py | 62 ++++ ...workpage_f_project_active_text_and_more.py | 21 ++ ..._ourworkpage_no_projects_found_and_more.py | 38 +++ app/our_work/migrations/__init__.py | 0 app/our_work/models.py | 225 ++++++++++++++ .../components/FilterCategoryPage.html | 14 + .../components/FilterCategorySnippet.html | 14 + .../our_work/components/MapboxMarker.html | 12 + .../our_work/components/MapboxScript.html | 15 + .../components/ProjectSortOption.html | 4 + .../components/ProjectStatusOption.html | 4 + .../templates/our_work/our_work_page.html | 274 ++++++++++++++++++ app/our_work/tests.py | 3 + app/our_work/views.py | 3 + ...ove_partnerwithuspage_partnership_types.py | 17 ++ app/partners/models.py | 15 +- .../partners/partner_with_us_page.html | 8 +- ...projecttype_individualprojectpage_types.py | 26 ++ ...ividualprojectpage_location_coordinates.py | 18 ++ ...30_individualprojectpage_project_active.py | 18 ++ .../migrations/0031_projectstatus_and_more.py | 30 ++ .../0032_alter_projectstatus_options.py | 17 ++ ...dualprojectpage_project_status_and_more.py | 23 ++ .../0034_projectownerpage_types_title.py | 18 ++ app/projects/models.py | 51 +++- .../projects/individual_project_page.html | 67 +++-- app/tech/models.py | 8 + .../ui/components/BasePageHeader.html | 5 +- .../ui/components/CTABodyPanelBase.html | 3 +- .../FooterBannerWithTextAndLink.html | 3 +- .../ui/components/PageHeaderWithBlur.html | 3 +- .../dogear_boxes/DogearContent.html | 3 +- .../dogear_boxes/SpecialDogearLinkBox.html | 3 +- .../events/EventPreviewBlockEvent.html | 3 +- .../ui/components/icon_svgs/FilterIcon.html | 3 + .../ui/components/icon_svgs/MapIcon.html | 5 + .../ui/components/icon_svgs/RefreshIcon.html | 2 +- .../ui/components/icon_svgs/ViewGridIcon.html | 5 + .../impact_areas/ImpactAreaPreviewBlock.html | 3 +- .../ImpactAreaPreviewBlockMini.html | 10 + .../MappingHubPreviewExtendedBlock.html | 3 +- .../MappingHubPreviewProjectsBlock.html | 9 + .../misc_panels/LinkBlockWithImage.html | 3 +- .../navigation/FooterNavigation.html | 3 +- .../news/NewsPreviewBlockProjects.html | 3 +- .../programs/ProgramPreviewBlockBase.html | 3 +- .../sections/BaseSectionWithImage.html | 5 +- .../components/sections/LinkListSection.html | 3 +- .../SmallSectionWithHeaderAndDivider.html | 3 +- .../CheckOutOpportunitiesSection.html | 5 +- .../home/components/ImpactAreasPanel.html | 3 +- .../home/components/MappingHubsPanel.html | 11 +- home/templatetags/homepage_tags.py | 6 + hot_osm/settings/base.py | 9 + hot_osm/templates/base.html | 2 + poetry.lock | 19 +- pyproject.toml | 1 + 63 files changed, 1126 insertions(+), 92 deletions(-) create mode 100644 app/core/migrations/0008_partnertype_type_description_partnertype_type_icon.py create mode 100644 app/our_work/__init__.py create mode 100644 app/our_work/admin.py create mode 100644 app/our_work/apps.py create mode 100644 app/our_work/migrations/0001_initial.py create mode 100644 app/our_work/migrations/0002_remove_ourworkpage_f_project_active_text_and_more.py create mode 100644 app/our_work/migrations/0003_ourworkpage_no_projects_found_and_more.py create mode 100644 app/our_work/migrations/__init__.py create mode 100644 app/our_work/models.py create mode 100644 app/our_work/templates/our_work/components/FilterCategoryPage.html create mode 100644 app/our_work/templates/our_work/components/FilterCategorySnippet.html create mode 100644 app/our_work/templates/our_work/components/MapboxMarker.html create mode 100644 app/our_work/templates/our_work/components/MapboxScript.html create mode 100644 app/our_work/templates/our_work/components/ProjectSortOption.html create mode 100644 app/our_work/templates/our_work/components/ProjectStatusOption.html create mode 100644 app/our_work/templates/our_work/our_work_page.html create mode 100644 app/our_work/tests.py create mode 100644 app/our_work/views.py create mode 100644 app/partners/migrations/0007_remove_partnerwithuspage_partnership_types.py create mode 100644 app/projects/migrations/0028_projecttype_individualprojectpage_types.py create mode 100644 app/projects/migrations/0029_individualprojectpage_location_coordinates.py create mode 100644 app/projects/migrations/0030_individualprojectpage_project_active.py create mode 100644 app/projects/migrations/0031_projectstatus_and_more.py create mode 100644 app/projects/migrations/0032_alter_projectstatus_options.py create mode 100644 app/projects/migrations/0033_remove_individualprojectpage_project_status_and_more.py create mode 100644 app/projects/migrations/0034_projectownerpage_types_title.py create mode 100644 app/ui/templates/ui/components/icon_svgs/FilterIcon.html create mode 100644 app/ui/templates/ui/components/icon_svgs/MapIcon.html create mode 100644 app/ui/templates/ui/components/icon_svgs/ViewGridIcon.html create mode 100644 app/ui/templates/ui/components/impact_areas/ImpactAreaPreviewBlockMini.html create mode 100644 app/ui/templates/ui/components/mapping_hub/MappingHubPreviewProjectsBlock.html diff --git a/app/core/migrations/0008_partnertype_type_description_partnertype_type_icon.py b/app/core/migrations/0008_partnertype_type_description_partnertype_type_icon.py new file mode 100644 index 0000000..0d0f720 --- /dev/null +++ b/app/core/migrations/0008_partnertype_type_description_partnertype_type_icon.py @@ -0,0 +1,26 @@ +# Generated by Django 4.2.7 on 2024-08-07 19:01 + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailimages', '0025_alter_image_file_alter_rendition_file'), + ('core', '0007_partnertype_partner_partner_type'), + ] + + operations = [ + migrations.AddField( + model_name='partnertype', + name='type_description', + field=wagtail.fields.RichTextField(blank=True), + ), + migrations.AddField( + model_name='partnertype', + name='type_icon', + field=models.ForeignKey(help_text='Icon for the partner type', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image'), + ), + ] diff --git a/app/core/models.py b/app/core/models.py index 49732e3..70b32cc 100644 --- a/app/core/models.py +++ b/app/core/models.py @@ -2,7 +2,7 @@ from django.db import models from wagtail.models import Page -from wagtail.fields import StreamField +from wagtail.fields import StreamField, RichTextField from wagtail.blocks import CharBlock, StreamBlock, StructBlock, URLBlock, RichTextBlock, PageChooserBlock from wagtail.snippets.models import register_snippet from wagtail.admin.panels import FieldPanel, MultiFieldPanel, InlinePanel @@ -11,9 +11,21 @@ @register_snippet class PartnerType(models.Model): type_name = models.CharField() + type_icon = models.ForeignKey( + "wagtailimages.Image", + null=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Icon for the partner type" + ) + type_description = RichTextField(blank=True) panels = [ - FieldPanel("type_name") + FieldPanel("type_name"), + MultiFieldPanel([ + FieldPanel('type_icon'), + FieldPanel('type_description'), + ], heading="These will show in the Partner With Us page - an info block is automatically created for each partner type.") ] def __str__(self): diff --git a/app/impact_areas/templates/impact_areas/individual_impact_area_page.html b/app/impact_areas/templates/impact_areas/individual_impact_area_page.html index 051925b..8c05f76 100644 --- a/app/impact_areas/templates/impact_areas/individual_impact_area_page.html +++ b/app/impact_areas/templates/impact_areas/individual_impact_area_page.html @@ -33,15 +33,8 @@ {% comment %} PROJECTS {% endcomment %} -
-
-
- {% include "ui/components/SectionHeadingWithUnderline.html" with title=page.get_parent.specific.projects_title %} -
-

- {% include "ui/components/BaseLink.html" with linktext=page.get_parent.specific.view_all_projects_text linkurl=page.view_all_projects_link %} -

-
+
+ {% include "ui/components/FlexTitleWithLink.html" with title=page.get_parent.specific.projects_title linktext=page.get_parent.specific.view_all_projects_text linkurl=page.view_all_projects_link titleclass="text-h2" %}
{% for project in projects %} {% include "ui/components/projects/ProjectPreviewBlockNews.html" with project=project showimage=True %} @@ -73,14 +66,7 @@

{% for area in other_impact_areas %} {% if area != page %} - -
- {% image area.external_icon fill-200x200 class="px-10" %} -

- {{ area.title }} -

-
-
+ {% include "ui/components/impact_areas/ImpactAreaPreviewBlockMini.html" %} {% endif %} {% endfor %}
diff --git a/app/our_work/__init__.py b/app/our_work/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/our_work/admin.py b/app/our_work/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/app/our_work/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/app/our_work/apps.py b/app/our_work/apps.py new file mode 100644 index 0000000..fdc001f --- /dev/null +++ b/app/our_work/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class OurWorkConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'app.our_work' diff --git a/app/our_work/migrations/0001_initial.py b/app/our_work/migrations/0001_initial.py new file mode 100644 index 0000000..48d063f --- /dev/null +++ b/app/our_work/migrations/0001_initial.py @@ -0,0 +1,62 @@ +# Generated by Django 4.2.7 on 2024-08-06 21:22 + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('wagtailimages', '0025_alter_image_file_alter_rendition_file'), + ('wagtailcore', '0089_log_entry_data_json_null_to_object'), + ] + + operations = [ + migrations.CreateModel( + name='OurWorkPage', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')), + ('programs_title', models.CharField(default='Highlighted Programs')), + ('programs_description', wagtail.fields.RichTextField(blank=True)), + ('view_all_programs_text', models.CharField(default='View all programs')), + ('view_all_programs_link', wagtail.fields.StreamField([('page', wagtail.blocks.PageChooserBlock()), ('url', wagtail.blocks.URLBlock())], blank=True, use_json_field=True)), + ('highlighted_programs', wagtail.fields.StreamField([('program', wagtail.blocks.PageChooserBlock(page_type=['programs.IndividualProgramPage']))], blank=True, null=True, use_json_field=True)), + ('projects_title', models.CharField(default='Projects')), + ('search_keyword_text', models.CharField(default='Search by keyword')), + ('sort_new_text', models.CharField(default='Sort by New')), + ('sort_old_text', models.CharField(default='Sort by Old')), + ('sort_titlea_text', models.CharField(default='Sort by Name Alphabetical')), + ('sort_titlez_text', models.CharField(default='Sort by Name Reverse Alphabetical')), + ('filters_text', models.CharField(default='Filters')), + ('view_grid_text', models.CharField(default='View Grid')), + ('view_map_text', models.CharField(default='View Map')), + ('f_impact_areas_text', models.CharField(default='Impact Areas')), + ('f_open_mapping_hubs_text', models.CharField(default='Open Mapping Hubs')), + ('f_projects_by_programme_text', models.CharField(default='Projects by Programme')), + ('f_projects_by_type_text', models.CharField(default='Projects by Type')), + ('f_project_status_text', models.CharField(default='Project Status')), + ('f_project_active_text', models.CharField(default='Active')), + ('f_project_complete_text', models.CharField(default='Complete')), + ('f_apply_filter_text', models.CharField(default='Apply Filter')), + ('f_reset_filters_text', models.CharField(default='Reset Filters')), + ('load_more_projects_text', models.CharField(default='Load More Projects')), + ('impact_area_title', models.CharField(default='See Projects by Impact Area')), + ('open_mapping_hub_title', models.CharField(default='See Projects by Open Mapping Hub')), + ('red_box_title', models.CharField(default="See all of HOT's projects")), + ('red_box_link_text', models.CharField(default='Explore projects')), + ('red_box_link', wagtail.fields.StreamField([('page', wagtail.blocks.PageChooserBlock()), ('url', wagtail.blocks.URLBlock())], blank=True, use_json_field=True)), + ('black_box_title', models.CharField(default='See the many ways to get involved with HOT and open mapping')), + ('black_box_link_text', models.CharField(default='Get involved')), + ('black_box_link', wagtail.fields.StreamField([('page', wagtail.blocks.PageChooserBlock()), ('url', wagtail.blocks.URLBlock())], blank=True, use_json_field=True)), + ('header_image', models.ForeignKey(blank=True, help_text='Header image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image')), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + ] diff --git a/app/our_work/migrations/0002_remove_ourworkpage_f_project_active_text_and_more.py b/app/our_work/migrations/0002_remove_ourworkpage_f_project_active_text_and_more.py new file mode 100644 index 0000000..bd0686b --- /dev/null +++ b/app/our_work/migrations/0002_remove_ourworkpage_f_project_active_text_and_more.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.7 on 2024-08-12 16:09 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('our_work', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='ourworkpage', + name='f_project_active_text', + ), + migrations.RemoveField( + model_name='ourworkpage', + name='f_project_complete_text', + ), + ] diff --git a/app/our_work/migrations/0003_ourworkpage_no_projects_found_and_more.py b/app/our_work/migrations/0003_ourworkpage_no_projects_found_and_more.py new file mode 100644 index 0000000..b201471 --- /dev/null +++ b/app/our_work/migrations/0003_ourworkpage_no_projects_found_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 4.2.7 on 2024-08-12 23:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('our_work', '0002_remove_ourworkpage_f_project_active_text_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='ourworkpage', + name='no_projects_found', + field=models.CharField(default='No projects found with the applied filters.'), + ), + migrations.AlterField( + model_name='ourworkpage', + name='black_box_link_text', + field=models.CharField(default='Get Involved with HOT'), + ), + migrations.AlterField( + model_name='ourworkpage', + name='black_box_title', + field=models.CharField(default='Check many opportunities to get involved with HOT!'), + ), + migrations.AlterField( + model_name='ourworkpage', + name='red_box_link_text', + field=models.CharField(default='View all events'), + ), + migrations.AlterField( + model_name='ourworkpage', + name='red_box_title', + field=models.CharField(default='Check our upcoming events!'), + ), + ] diff --git a/app/our_work/migrations/__init__.py b/app/our_work/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/our_work/models.py b/app/our_work/models.py new file mode 100644 index 0000000..e93f540 --- /dev/null +++ b/app/our_work/models.py @@ -0,0 +1,225 @@ +import re + +from django import forms +from django.db import models +from django.db.models import Q +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger +from django.http import JsonResponse + +from wagtail.models import Page +from wagtail.fields import RichTextField, StreamField +from wagtail.admin.panels import FieldPanel, MultiFieldPanel, PageChooserPanel +from wagtail.blocks import CharBlock, StreamBlock, StructBlock, URLBlock, RichTextBlock, PageChooserBlock +from modelcluster.fields import ParentalKey, ParentalManyToManyField + +from app.projects.models import IndividualProjectPage, ProjectType, ProjectStatus +from app.impact_areas.models import IndividualImpactAreaPage +from app.mapping_hubs.models import MappingHubProjectsPage, IndividualMappingHubPage +from app.programs.models import IndividualProgramPage +from app.core.models import LinkOrPageBlock + + +class OurWorkPage(Page): + def get_project_paginator(self, request, context): + projects_list = IndividualProjectPage.objects.live().filter(locale=context['page'].locale) + + keyword = request.GET.get('keyword', '') + + if keyword: + projects_list = projects_list.search(keyword).get_queryset() + + p_types = ProjectType.objects.all() + query = Q() + for p_type in p_types: + if request.GET.get(str(p_type), ''): + query = query | Q(types=p_type) + projects_list = projects_list.filter(query).distinct() + + if request.GET.get("status", 'statusnone') != "statusnone": + statuses = ProjectStatus.objects.all() + query = Q() + for status in statuses: + if request.GET.get("status", '') == f"status{status.id}": + query = query | Q(project_status=status) + break + projects_list = projects_list.filter(query).distinct() + + hubs = IndividualMappingHubPage.objects.live().filter(locale=context['page'].locale) + query = Q() + for hub in hubs: + if request.GET.get(f"hub{hub.id}", ''): + query = query | Q(region_hub_list__contains=[{'type': 'region_hub', 'value': hub.id }]) + projects_list = projects_list.filter(query).distinct() + + impact_areas = IndividualImpactAreaPage.objects.live().filter(locale=context['page'].locale) + query = Q() + for area in impact_areas: + if request.GET.get(f"ia{area.id}", ''): + print(area.id, area) + query = query | Q(impact_area_list__contains=[{'type': 'impact_area', 'value': area.id }]) + projects_list = projects_list.filter(query).distinct() + + programs = IndividualProgramPage.objects.live().filter(locale=context['page'].locale) + query = Q() + for program in programs: + if request.GET.get(f"pg{program.id}", ''): + query = query | Q(owner_program=program) + projects_list = projects_list.filter(query).distinct() + + match request.GET.get('sort', ''): + case 'sort.titlea': + projects_list = projects_list.order_by('title') + case 'sort.titlez': + projects_list = projects_list.order_by('-title') + case _: + projects_list = projects_list.order_by('title') + + page = request.GET.get('page', 1) + paginator = Paginator(projects_list, 8) # if you want more/less items per page (i.e., per load), change the number here to something else + try: + projects = paginator.page(page) + except PageNotAnInteger: + projects = paginator.page(1) + except EmptyPage: + projects = paginator.page(paginator.num_pages) + + return paginator, projects + + def get_context(self, request, *args, **kwargs): + context = super().get_context(request, *args, **kwargs) + + paginator, projects = self.get_project_paginator(request, context) + + context['projects'] = projects + context['paginator'] = paginator + context['impact_areas'] = IndividualImpactAreaPage.objects.live().filter(locale=context['page'].locale) + context['hubs'] = IndividualMappingHubPage.objects.live().filter(locale=context['page'].locale) + context['hubs_projects'] = MappingHubProjectsPage.objects.live().filter(locale=context['page'].locale) + context['programs'] = IndividualProgramPage.objects.live().filter(locale=context['page'].locale) + context['types'] = ProjectType.objects.all() + context['statuses'] = ProjectStatus.objects.all() + return context + + def serve(self, request, *args, **kwargs): + if request.GET.get('projects', False): + context = super().get_context(request, *args, **kwargs) + _, projects = self.get_project_paginator(request, context) + + features = [] + for project in projects: + if not project.location_coordinates: + continue + coordinates = [float(x) for x in re.findall("\(([^\)]+)\)", project.location_coordinates)[0].split()] + features += [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": coordinates + }, + "properties": { + "title": f"{project.title}", + "description": f"{project.intro}", + "id": f"{project.id}", + } + } + ] + + geojson = { + "type": "FeatureCollection", + "features": features, + } + + return JsonResponse(geojson) + + return super().serve(request, *args, **kwargs) + + max_count = 1 + + header_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Header image", + ) + + programs_title = models.CharField(default="Highlighted Programs") + programs_description = RichTextField(blank=True) + view_all_programs_text = models.CharField(default="View all programs") + view_all_programs_link = StreamField(LinkOrPageBlock(), use_json_field=True, blank=True) + highlighted_programs = StreamField([('program', PageChooserBlock(page_type="programs.IndividualProgramPage"))], use_json_field=True, null=True, blank=True) + + projects_title = models.CharField(default="Projects") + search_keyword_text = models.CharField(default="Search by keyword") + sort_new_text = models.CharField(default="Sort by New") + sort_old_text = models.CharField(default="Sort by Old") + sort_titlea_text = models.CharField(default="Sort by Name Alphabetical") + sort_titlez_text = models.CharField(default="Sort by Name Reverse Alphabetical") + filters_text = models.CharField(default="Filters") + view_grid_text = models.CharField(default="View Grid") + view_map_text = models.CharField(default="View Map") + + f_impact_areas_text = models.CharField(default="Impact Areas") + f_open_mapping_hubs_text = models.CharField(default="Open Mapping Hubs") + f_projects_by_programme_text = models.CharField(default="Projects by Programme") + f_projects_by_type_text = models.CharField(default="Projects by Type") + f_project_status_text = models.CharField(default="Project Status") + f_apply_filter_text = models.CharField(default="Apply Filter") + f_reset_filters_text = models.CharField(default="Reset Filters") + + load_more_projects_text = models.CharField(default="Load More Projects") + no_projects_found = models.CharField(default="No projects found with the applied filters.") + impact_area_title = models.CharField(default="See Projects by Impact Area") + open_mapping_hub_title = models.CharField(default="See Projects by Open Mapping Hub") + + red_box_title = models.CharField(default="Check our upcoming events!") + red_box_link_text = models.CharField(default="View all events") + red_box_link = StreamField(LinkOrPageBlock(), use_json_field=True, blank=True) + black_box_title = models.CharField(default="Check many opportunities to get involved with HOT!") + black_box_link_text = models.CharField(default="Get Involved with HOT") + black_box_link = StreamField(LinkOrPageBlock(), use_json_field=True, blank=True) + + content_panels = Page.content_panels + [ + FieldPanel('header_image'), + MultiFieldPanel([ + FieldPanel('programs_title'), + FieldPanel('programs_description'), + FieldPanel('view_all_programs_text'), + FieldPanel('view_all_programs_link'), + FieldPanel('highlighted_programs'), + ], heading="Programs"), + MultiFieldPanel([ + FieldPanel('projects_title'), + FieldPanel('search_keyword_text'), + FieldPanel('sort_new_text'), + FieldPanel('sort_old_text'), + FieldPanel('sort_titlea_text'), + FieldPanel('sort_titlez_text'), + FieldPanel('filters_text'), + FieldPanel('view_grid_text'), + FieldPanel('view_map_text'), + MultiFieldPanel([ + FieldPanel('f_impact_areas_text'), + FieldPanel('f_open_mapping_hubs_text'), + FieldPanel('f_projects_by_programme_text'), + FieldPanel('f_projects_by_type_text'), + FieldPanel('f_project_status_text'), + FieldPanel('f_apply_filter_text'), + FieldPanel('f_reset_filters_text'), + ], heading="Filters Menu"), + FieldPanel('load_more_projects_text'), + FieldPanel('no_projects_found'), + ], heading="Projects Section"), + MultiFieldPanel([ + FieldPanel('impact_area_title'), + FieldPanel('open_mapping_hub_title'), + FieldPanel('red_box_title'), + FieldPanel('red_box_link_text'), + FieldPanel('red_box_link'), + FieldPanel('black_box_title'), + FieldPanel('black_box_link_text'), + FieldPanel('black_box_link'), + ], heading="Bottom Area"), + ] diff --git a/app/our_work/templates/our_work/components/FilterCategoryPage.html b/app/our_work/templates/our_work/components/FilterCategoryPage.html new file mode 100644 index 0000000..d8cadc7 --- /dev/null +++ b/app/our_work/templates/our_work/components/FilterCategoryPage.html @@ -0,0 +1,14 @@ +
+

+ {{title}} +

+
+
+ {% for p in pages %} +
+ + +
+ {% endfor %} +
+
\ No newline at end of file diff --git a/app/our_work/templates/our_work/components/FilterCategorySnippet.html b/app/our_work/templates/our_work/components/FilterCategorySnippet.html new file mode 100644 index 0000000..f2d18fb --- /dev/null +++ b/app/our_work/templates/our_work/components/FilterCategorySnippet.html @@ -0,0 +1,14 @@ +
+

+ {{title}} +

+
+
+ {% for snippet in snippets %} +
+ + +
+ {% endfor %} +
+
\ No newline at end of file diff --git a/app/our_work/templates/our_work/components/MapboxMarker.html b/app/our_work/templates/our_work/components/MapboxMarker.html new file mode 100644 index 0000000..1a5fea0 --- /dev/null +++ b/app/our_work/templates/our_work/components/MapboxMarker.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/our_work/templates/our_work/components/MapboxScript.html b/app/our_work/templates/our_work/components/MapboxScript.html new file mode 100644 index 0000000..3b707c2 --- /dev/null +++ b/app/our_work/templates/our_work/components/MapboxScript.html @@ -0,0 +1,15 @@ +{% load homepage_tags %} +{% get_mapbox_key as mapbox_key %} + + \ No newline at end of file diff --git a/app/our_work/templates/our_work/components/ProjectSortOption.html b/app/our_work/templates/our_work/components/ProjectSortOption.html new file mode 100644 index 0000000..8e3320f --- /dev/null +++ b/app/our_work/templates/our_work/components/ProjectSortOption.html @@ -0,0 +1,4 @@ +
+ + +
\ No newline at end of file diff --git a/app/our_work/templates/our_work/components/ProjectStatusOption.html b/app/our_work/templates/our_work/components/ProjectStatusOption.html new file mode 100644 index 0000000..104cbca --- /dev/null +++ b/app/our_work/templates/our_work/components/ProjectStatusOption.html @@ -0,0 +1,4 @@ +
+ + +
\ No newline at end of file diff --git a/app/our_work/templates/our_work/our_work_page.html b/app/our_work/templates/our_work/our_work_page.html new file mode 100644 index 0000000..fe93bcb --- /dev/null +++ b/app/our_work/templates/our_work/our_work_page.html @@ -0,0 +1,274 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} + +{% block body_class %}template-ourworkpage{% endblock %} +{% block extra_css %} + {% compress css %} + {% endcompress css %} +{% endblock extra_css %} + +{% block extra_head %} + + +{% endblock %} + +{% block content %} + {% include "ui/components/PageHeaderWithBlur.html" with title=page.title image=page.header_image endinlarge=True full_length=True %} + +
+
+
+
+

+ {{ page.programs_title }} +

+
+ {{ page.programs_description|richtext }} +
+
+
+ {% include "ui/components/BaseLink.html" with linktext=page.view_all_programs_text linkurl=page.view_all_programs_url %} +
+
+
+ {% include "ui/components/programs/ProgramCarouselBlock.html" with programs=page.highlighted_programs %} +
+ + {% comment %} FILTERS {% endcomment %} +
+

+ {{ page.projects_title }} +

+
+
+ {% comment %} KEYWORD SEARCH {% endcomment %} +
+ + {% include "ui/components/icon_svgs/SearchIcon.html" with class="text-hot-red mx-3" %} +
+ + {% comment %} SORT {% endcomment %} +
+
+

+ {{page.sort_titlea_text}} +

+ {% include "ui/components/icon_svgs/LinkCaret.html" with class="rotate-90 text-hot-red" %} +
+
+
+ {% include "./components/ProjectSortOption.html" with sort_by=page.sort_titlea_text sort_id="sort.titlea" %} + {% include "./components/ProjectSortOption.html" with sort_by=page.sort_titlez_text sort_id="sort.titlez" %} +
+
+ + + +
+
+

+ {{page.filters_text}} + {% include "ui/components/icon_svgs/FilterIcon.html" %} +

+
+ +
+
+

+ {% include "ui/components/icon_svgs/ViewGridIcon.html" %} + {{page.view_grid_text}} +

+
+
+

+ {% include "ui/components/icon_svgs/MapIcon.html" %} + {{page.view_map_text}} +

+
+
+
+
+ + {% comment %} MAP AND FILTER CONTAINER {% endcomment %} +
+
+ {% comment %} MAP {% endcomment %} +
+ {% comment %} PROJECTS {% endcomment %} + +
+ + {% comment %} FILTERS {% endcomment %} +
+
+ {% include "./components/FilterCategoryPage.html" with pages=impact_areas denoter="ia" title=page.f_impact_areas_text %} + {% include "./components/FilterCategoryPage.html" with pages=hubs denoter="hub" title=page.f_open_mapping_hubs_text %} + {% include "./components/FilterCategoryPage.html" with pages=programs denoter="pg" title=page.f_projects_by_programme_text %} + {% include "./components/FilterCategorySnippet.html" with snippets=types denoter="pt" title=page.f_projects_by_type_text %} + +
+

+ {{page.f_project_status_text}} +

+
+
+
+ {% include "./components/ProjectStatusOption.html" with status_by="---" status_id="none" %} + {% for status in statuses %} + {% include "./components/ProjectStatusOption.html" with status_by=status status_id=status.id %} + {% endfor %} +
+
+
+
+
+ +
+
+
+ + {% comment %} PROJECTS LIST GRID VIEW {% endcomment %} +
+
+ {% for project in projects %} + {% include "ui/components/projects/ProjectPreviewBlockNews.html" with project=project.specific showimage=True %} + {% endfor %} + {% if not projects %} +

+ {{page.no_projects_found}} +

+ {% endif %} +
+

+ {% if projects.has_next %} + + {% endif %} +

+
+
+ +
+

+ {{page.impact_area_title}} +

+
+ {% for area in impact_areas %} + {% include "ui/components/impact_areas/ImpactAreaPreviewBlockMini.html" with link_addendum="#projects-section" %} + {% endfor %} +
+
+ +
+

+ {{page.open_mapping_hub_title}} +

+
+ {% for hub_project in hubs_projects %} + {% include "ui/components/mapping_hub/MappingHubPreviewProjectsBlock.html" %} + {% endfor %} +
+
+ +
+
+ {% include "ui/components/dogear_boxes/DogearRed.html" with title=page.red_box_title linktext=page.red_box_link_text linkurl=page.red_box_link %} +
+
+ {% include "ui/components/dogear_boxes/DogearBlack.html" with title=page.black_box_title linktext=page.black_box_link_text linkurl=black_box_link %} +
+
+
+
+ + {% include "./components/MapboxScript.html" %} + +{% endblock %} diff --git a/app/our_work/tests.py b/app/our_work/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/app/our_work/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/app/our_work/views.py b/app/our_work/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/app/our_work/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/app/partners/migrations/0007_remove_partnerwithuspage_partnership_types.py b/app/partners/migrations/0007_remove_partnerwithuspage_partnership_types.py new file mode 100644 index 0000000..78832ac --- /dev/null +++ b/app/partners/migrations/0007_remove_partnerwithuspage_partnership_types.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.7 on 2024-08-07 19:01 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('partners', '0006_ourpartnerspage_filter_button_text'), + ] + + operations = [ + migrations.RemoveField( + model_name='partnerwithuspage', + name='partnership_types', + ), + ] diff --git a/app/partners/models.py b/app/partners/models.py index 9377506..31f32d4 100644 --- a/app/partners/models.py +++ b/app/partners/models.py @@ -10,15 +10,14 @@ from app.core.models import LinkOrPageBlock, Partner, PartnerType -# The "partners" snippet is in the core app's models. +# The "partners" and "partner types" snippets are in the core app's models. class PartnerWithUsPage(Page): def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) - - partners = Partner.objects.all() - context['partners'] = partners + context['partners'] = Partner.objects.all() + context['partner_types'] = PartnerType.objects.all() return context max_count = 1 @@ -36,13 +35,6 @@ def get_context(self, request, *args, **kwargs): intro = RichTextField(blank=True) partnership_types_title = models.CharField(default="Types of Partnerships") - partnership_types = StreamField([ - ('blocks', StructBlock([ - ('icon', ImageChooserBlock()), - ('title', CharBlock()), - ('description', RichTextBlock()) - ])) - ], use_json_field=True, null=True, blank=True, help_text="Blocks to be shown under the Types of Partnerships section.") meet_our_partners_title = models.CharField(default="Meet Our Partners") view_all_partners_text = models.CharField(default="View All Partners") @@ -63,7 +55,6 @@ def get_context(self, request, *args, **kwargs): FieldPanel('intro'), MultiFieldPanel([ FieldPanel('partnership_types_title'), - FieldPanel('partnership_types'), ], heading="Types of Partnerships"), MultiFieldPanel([ FieldPanel('meet_our_partners_title'), diff --git a/app/partners/templates/partners/partner_with_us_page.html b/app/partners/templates/partners/partner_with_us_page.html index 491f0d3..252921b 100644 --- a/app/partners/templates/partners/partner_with_us_page.html +++ b/app/partners/templates/partners/partner_with_us_page.html @@ -22,14 +22,14 @@ {% include "ui/components/SectionHeadingWithUnderline.html" with title=page.partnership_types_title %}
- {% for block in page.partnership_types %} + {% for ptype in partner_types %}
- {% image block.value.icon original class="h-8 w-8 mt-2" %} + {% image ptype.type_icon original class="h-8 w-8 mt-2" %}

- {{block.value.title}} + {{ptype.type_name}}

- {{block.value.description}} + {{ptype.type_description|richtext}}
{% endfor %} diff --git a/app/projects/migrations/0028_projecttype_individualprojectpage_types.py b/app/projects/migrations/0028_projecttype_individualprojectpage_types.py new file mode 100644 index 0000000..07598cf --- /dev/null +++ b/app/projects/migrations/0028_projecttype_individualprojectpage_types.py @@ -0,0 +1,26 @@ +# Generated by Django 4.2.7 on 2024-08-06 21:22 + +from django.db import migrations, models +import modelcluster.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0027_individualprojectpage_intro'), + ] + + operations = [ + migrations.CreateModel( + name='ProjectType', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('type_name', models.CharField()), + ], + ), + migrations.AddField( + model_name='individualprojectpage', + name='types', + field=modelcluster.fields.ParentalManyToManyField(blank=True, to='projects.projecttype'), + ), + ] diff --git a/app/projects/migrations/0029_individualprojectpage_location_coordinates.py b/app/projects/migrations/0029_individualprojectpage_location_coordinates.py new file mode 100644 index 0000000..2202bc6 --- /dev/null +++ b/app/projects/migrations/0029_individualprojectpage_location_coordinates.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-08-07 23:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0028_projecttype_individualprojectpage_types'), + ] + + operations = [ + migrations.AddField( + model_name='individualprojectpage', + name='location_coordinates', + field=models.CharField(blank=True, max_length=250, null=True), + ), + ] diff --git a/app/projects/migrations/0030_individualprojectpage_project_active.py b/app/projects/migrations/0030_individualprojectpage_project_active.py new file mode 100644 index 0000000..01b0dcb --- /dev/null +++ b/app/projects/migrations/0030_individualprojectpage_project_active.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-08-08 21:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0029_individualprojectpage_location_coordinates'), + ] + + operations = [ + migrations.AddField( + model_name='individualprojectpage', + name='project_active', + field=models.BooleanField(default=True), + ), + ] diff --git a/app/projects/migrations/0031_projectstatus_and_more.py b/app/projects/migrations/0031_projectstatus_and_more.py new file mode 100644 index 0000000..9b7dd9c --- /dev/null +++ b/app/projects/migrations/0031_projectstatus_and_more.py @@ -0,0 +1,30 @@ +# Generated by Django 4.2.7 on 2024-08-08 22:40 + +from django.db import migrations, models +import modelcluster.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0030_individualprojectpage_project_active'), + ] + + operations = [ + migrations.CreateModel( + name='ProjectStatus', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('status_name', models.CharField()), + ], + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='project_active', + ), + migrations.AddField( + model_name='individualprojectpage', + name='project_status', + field=modelcluster.fields.ParentalManyToManyField(blank=True, to='projects.projectstatus'), + ), + ] diff --git a/app/projects/migrations/0032_alter_projectstatus_options.py b/app/projects/migrations/0032_alter_projectstatus_options.py new file mode 100644 index 0000000..a9262a0 --- /dev/null +++ b/app/projects/migrations/0032_alter_projectstatus_options.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.7 on 2024-08-12 16:09 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0031_projectstatus_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='projectstatus', + options={'verbose_name_plural': 'Project statuses'}, + ), + ] diff --git a/app/projects/migrations/0033_remove_individualprojectpage_project_status_and_more.py b/app/projects/migrations/0033_remove_individualprojectpage_project_status_and_more.py new file mode 100644 index 0000000..46f82d4 --- /dev/null +++ b/app/projects/migrations/0033_remove_individualprojectpage_project_status_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.7 on 2024-08-12 22:15 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0032_alter_projectstatus_options'), + ] + + operations = [ + migrations.RemoveField( + model_name='individualprojectpage', + name='project_status', + ), + migrations.AddField( + model_name='individualprojectpage', + name='project_status', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='projects.projectstatus'), + ), + ] diff --git a/app/projects/migrations/0034_projectownerpage_types_title.py b/app/projects/migrations/0034_projectownerpage_types_title.py new file mode 100644 index 0000000..ab05eb5 --- /dev/null +++ b/app/projects/migrations/0034_projectownerpage_types_title.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-08-13 17:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0033_remove_individualprojectpage_project_status_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='projectownerpage', + name='types_title', + field=models.CharField(default='Project Type'), + ), + ] diff --git a/app/projects/models.py b/app/projects/models.py index ea22cf0..a651b85 100644 --- a/app/projects/models.py +++ b/app/projects/models.py @@ -8,6 +8,10 @@ from wagtail.admin.panels import FieldPanel, MultiFieldPanel, PageChooserPanel from wagtail.blocks import CharBlock, StreamBlock, StructBlock, URLBlock, RichTextBlock, PageChooserBlock from wagtail.search import index +from wagtail.snippets.models import register_snippet + +from wagtailgeowidget.panels import LeafletPanel + from modelcluster.fields import ParentalKey, ParentalManyToManyField @@ -54,6 +58,7 @@ def get_context(self, request, *args, **kwargs): duration_title = models.CharField(default="Duration") partners_title = models.CharField(default="Partners") tools_title = models.CharField(default="Tools") + types_title = models.CharField(default="Project Type") contact_title = models.CharField(default="Contact") related_news_title = models.CharField(default="Related News") @@ -82,6 +87,7 @@ def get_context(self, request, *args, **kwargs): FieldPanel('duration_title'), FieldPanel('partners_title'), FieldPanel('tools_title'), + FieldPanel('types_title'), FieldPanel('contact_title'), MultiFieldPanel([ FieldPanel('related_news_title'), @@ -104,6 +110,33 @@ def get_context(self, request, *args, **kwargs): ] +@register_snippet +class ProjectType(models.Model): + type_name = models.CharField() + + panels = [ + FieldPanel("type_name") + ] + + def __str__(self): + return self.type_name + + +@register_snippet +class ProjectStatus(models.Model): + status_name = models.CharField() + + panels = [ + FieldPanel("status_name") + ] + + def __str__(self): + return self.status_name + + class Meta: + verbose_name_plural = "Project statuses" + + """ This page should only be created as a child of a ProjectOwnerPage! Its template depends on fields from the ProjectOwnerPage in order @@ -146,27 +179,28 @@ class IndividualProjectPage(Page): call_to_action_link_url = models.URLField(null=True, blank=True) # > SIDE BAR + project_status = models.ForeignKey( + "projects.ProjectStatus", + null=True, + blank=True, + on_delete=models.SET_NULL + ) impact_area_list = StreamField([('impact_area', PageChooserBlock(page_type="impact_areas.IndividualImpactAreaPage"))], use_json_field=True, null=True, blank=True) - region_hub_list = StreamField([('region_hub', PageChooserBlock(page_type="mapping_hubs.IndividualMappingHubPage"))], use_json_field=True, null=True, blank=True) - duration = models.CharField(default="Ongoing", blank=True) - partners_list = ParentalManyToManyField('core.Partner', blank=True) - tools = RichTextField(null=True, blank=True) # Will need to reference tools when they are added - contact = RichTextField(null=True, blank=True) - + types = ParentalManyToManyField('projects.ProjectType', blank=True) related_news = StreamField([ ('news_page', PageChooserBlock(page_type="news.IndividualNewsPage")) ], use_json_field=True, null=True, blank=True) - related_events = StreamField([ ('event_page', PageChooserBlock(page_type="events.IndividualEventPage")) ], use_json_field=True, null=True, blank=True) project_contributors = StreamField([('contributor', PageChooserBlock(page_type="members.IndividualMemberPage"))], use_json_field=True, null=True, blank=True) + location_coordinates = models.CharField(max_length=250, blank=True, null=True) search_fields = Page.search_fields + [ index.SearchField('title'), @@ -191,12 +225,14 @@ class IndividualProjectPage(Page): ], heading="Call to Action"), ], heading="Body"), MultiFieldPanel([ + FieldPanel('project_status', widget=forms.RadioSelect), FieldPanel('impact_area_list'), FieldPanel('region_hub_list'), FieldPanel('duration'), FieldPanel('partners_list', widget=forms.CheckboxSelectMultiple), FieldPanel('tools'), FieldPanel('contact'), + FieldPanel('types', widget=forms.CheckboxSelectMultiple), MultiFieldPanel([ FieldPanel('related_news'), FieldPanel('related_events'), @@ -204,5 +240,6 @@ class IndividualProjectPage(Page): ], heading="Sidebar"), MultiFieldPanel([ FieldPanel('project_contributors'), + LeafletPanel('location_coordinates'), ], heading="Extras") ] \ No newline at end of file diff --git a/app/projects/templates/projects/individual_project_page.html b/app/projects/templates/projects/individual_project_page.html index 1db1a43..dde6d2f 100644 --- a/app/projects/templates/projects/individual_project_page.html +++ b/app/projects/templates/projects/individual_project_page.html @@ -29,36 +29,59 @@
{% comment %} NOTE TO SELF: the "safe" thing is only needed temporarily until everything is put in {% endcomment %}
-
-

{{page.get_parent.specific.impact_areas_title}}

- {% for area in page.impact_area_list %} -

{{area.value.title}}

- {% endfor %} -
-
-

{{page.get_parent.specific.region_hub_title}}

- {% for hub in page.region_hub_list %} -

{{hub.value.title}}

- {% endfor %} -
+ {% if page.impact_area_list %} +
+

{{page.get_parent.specific.impact_areas_title}}

+ {% for area in page.impact_area_list %} +

{{area.value.title}}

+ {% endfor %} +
+ {% endif %} + + {% if page.region_hub_list %} +
+

{{page.get_parent.specific.region_hub_title}}

+ {% for hub in page.region_hub_list %} +

{{hub.value.title}}

+ {% endfor %} +
+ {% endif %} +

{{page.get_parent.specific.duration_title}}

{{page.duration}}

+ {%if page.project_status%}

{{page.project_status}}

{%endif%}
-
-

{{page.get_parent.specific.partners_title}}

- {% for partner in page.partners_list.all %} -

{{partner.partner_name}}

- {% endfor %} -
+ + {% if page.partners_list.all %} +
+

{{page.get_parent.specific.partners_title}}

+ {% for partner in page.partners_list.all %} +

{{partner.partner_name}}

+ {% endfor %} +
+ {% endif %} +

{{page.get_parent.specific.tools_title}}

{{page.tools|safe}}

-
-

{{page.get_parent.specific.contact_title}}

-

{{page.contact|safe}}

-
+ + {% if page.types.all %} +
+

{{page.get_parent.specific.types_title}}

+ {% for t in page.types.all %} +

{{t.type_name}}

+ {% endfor %} +
+ {% endif %} + + {% if page.contact %} +
+

{{page.get_parent.specific.contact_title}}

+

{{page.contact|safe}}

+
+ {% endif %}
{% comment %} RELATED NEWS {% endcomment %} diff --git a/app/tech/models.py b/app/tech/models.py index 37000c2..245cbbc 100644 --- a/app/tech/models.py +++ b/app/tech/models.py @@ -9,6 +9,10 @@ class IndividualTechStackPage(Page): + parent_page_types = [ + 'tech.TechProductSuitePage' + ] + header_image = models.ForeignKey( "wagtailimages.Image", null=True, @@ -64,6 +68,10 @@ class IndividualTechStackPage(Page): class TechProductSuitePage(Page): + subpage_types = [ + 'tech.IndividualTechStackPage' + ] + max_count = 1 header_image = models.ForeignKey( diff --git a/app/ui/templates/ui/components/BasePageHeader.html b/app/ui/templates/ui/components/BasePageHeader.html index cce8bb9..f646afd 100644 --- a/app/ui/templates/ui/components/BasePageHeader.html +++ b/app/ui/templates/ui/components/BasePageHeader.html @@ -7,6 +7,7 @@ Only one of either intro or subtitle should be present; you probably would not want both. {% endcomment %} +{% load wagtailcore_tags %} {% load wagtailimages_tags %} {% image image original as image_p %} @@ -21,13 +22,13 @@

{% if intro %}
- {{ intro|safe }} + {{ intro|richtext }}
{% endif %}
{% if subtitle %}
- {{ subtitle|safe }} + {{ subtitle|richtext }}
{% endif %}

diff --git a/app/ui/templates/ui/components/CTABodyPanelBase.html b/app/ui/templates/ui/components/CTABodyPanelBase.html index 7d6e8df..1270017 100644 --- a/app/ui/templates/ui/components/CTABodyPanelBase.html +++ b/app/ui/templates/ui/components/CTABodyPanelBase.html @@ -5,12 +5,13 @@ - linktext: string; the text shown for the link - linkurl: string; the url for the link {% endcomment %} +{% load wagtailcore_tags %}

{{ title }}

- {{ text|safe }} + {{ text|richtext }}

{% include "./BaseLink.html" %} diff --git a/app/ui/templates/ui/components/FooterBannerWithTextAndLink.html b/app/ui/templates/ui/components/FooterBannerWithTextAndLink.html index 4006b8c..243407f 100644 --- a/app/ui/templates/ui/components/FooterBannerWithTextAndLink.html +++ b/app/ui/templates/ui/components/FooterBannerWithTextAndLink.html @@ -4,6 +4,7 @@ - buttontext: A string, the text shown in the button - url: A string, the url for the button {% endcomment %} +{% load wagtailcore_tags %}

diff --git a/app/ui/templates/ui/components/dogear_boxes/DogearContent.html b/app/ui/templates/ui/components/dogear_boxes/DogearContent.html index 2b04df7..9ae98e0 100644 --- a/app/ui/templates/ui/components/dogear_boxes/DogearContent.html +++ b/app/ui/templates/ui/components/dogear_boxes/DogearContent.html @@ -8,12 +8,13 @@ - it's just using css styling, so you can use anything that a css style color would use (including variables, so you should probably use the colours from the hot_osm.css!) {% endcomment %} +{% load wagtailcore_tags %}

{{ title }}

{% if description %} -

{{description|safe}}

+

{{description|richtext}}

{% endif %}

diff --git a/app/ui/templates/ui/components/dogear_boxes/SpecialDogearLinkBox.html b/app/ui/templates/ui/components/dogear_boxes/SpecialDogearLinkBox.html index 495f24f..46eb0f2 100644 --- a/app/ui/templates/ui/components/dogear_boxes/SpecialDogearLinkBox.html +++ b/app/ui/templates/ui/components/dogear_boxes/SpecialDogearLinkBox.html @@ -5,6 +5,7 @@ - colour: a string; the colour that the box's accents should be (can be hex code or any other CSS compatible colour thing) {% endcomment %} +{% load wagtailcore_tags %}

@@ -12,7 +13,7 @@

{{ title }}

- {{ description|safe }} + {{ description|richtext }}
{% include "ui/components/BaseLink.html" %} diff --git a/app/ui/templates/ui/components/events/EventPreviewBlockEvent.html b/app/ui/templates/ui/components/events/EventPreviewBlockEvent.html index 31f2099..791d142 100644 --- a/app/ui/templates/ui/components/events/EventPreviewBlockEvent.html +++ b/app/ui/templates/ui/components/events/EventPreviewBlockEvent.html @@ -2,6 +2,7 @@ ==> PARAMETERS - event: an IndividualEventPage object; should be passed directly here {% endcomment %} +{% load wagtailcore_tags %} {% load wagtailimages_tags %} {% image event.image original as image_p %} @@ -35,7 +36,7 @@

{{event.title}}

-
{{event.intro|safe}}
+
{{event.intro|richtext}}

diff --git a/app/ui/templates/ui/components/icon_svgs/FilterIcon.html b/app/ui/templates/ui/components/icon_svgs/FilterIcon.html new file mode 100644 index 0000000..1aedbb6 --- /dev/null +++ b/app/ui/templates/ui/components/icon_svgs/FilterIcon.html @@ -0,0 +1,3 @@ + + + diff --git a/app/ui/templates/ui/components/icon_svgs/MapIcon.html b/app/ui/templates/ui/components/icon_svgs/MapIcon.html new file mode 100644 index 0000000..6f8d25c --- /dev/null +++ b/app/ui/templates/ui/components/icon_svgs/MapIcon.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/ui/templates/ui/components/icon_svgs/RefreshIcon.html b/app/ui/templates/ui/components/icon_svgs/RefreshIcon.html index d3b9f21..736e5f5 100644 --- a/app/ui/templates/ui/components/icon_svgs/RefreshIcon.html +++ b/app/ui/templates/ui/components/icon_svgs/RefreshIcon.html @@ -2,6 +2,6 @@ ==> PARAMETERS - class: string; the classes you want for this icon {% endcomment %} - + \ No newline at end of file diff --git a/app/ui/templates/ui/components/icon_svgs/ViewGridIcon.html b/app/ui/templates/ui/components/icon_svgs/ViewGridIcon.html new file mode 100644 index 0000000..0cb9163 --- /dev/null +++ b/app/ui/templates/ui/components/icon_svgs/ViewGridIcon.html @@ -0,0 +1,5 @@ + + + + + diff --git a/app/ui/templates/ui/components/impact_areas/ImpactAreaPreviewBlock.html b/app/ui/templates/ui/components/impact_areas/ImpactAreaPreviewBlock.html index 6ddb918..c8aefb6 100644 --- a/app/ui/templates/ui/components/impact_areas/ImpactAreaPreviewBlock.html +++ b/app/ui/templates/ui/components/impact_areas/ImpactAreaPreviewBlock.html @@ -2,6 +2,7 @@ ==> PARAMETERS - ia: an IndividualImpactAreaPage; should be passed directly here {% endcomment %} +{% load wagtailcore_tags %} {% load wagtailimages_tags %} {% image ia.header_image original as image_p %} @@ -16,7 +17,7 @@

- {{ ia.intro|safe }} + {{ ia.intro|richtext }}

diff --git a/app/ui/templates/ui/components/impact_areas/ImpactAreaPreviewBlockMini.html b/app/ui/templates/ui/components/impact_areas/ImpactAreaPreviewBlockMini.html new file mode 100644 index 0000000..f28dad3 --- /dev/null +++ b/app/ui/templates/ui/components/impact_areas/ImpactAreaPreviewBlockMini.html @@ -0,0 +1,10 @@ +{% load wagtailimages_tags %} + + +

+ \ No newline at end of file diff --git a/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewExtendedBlock.html b/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewExtendedBlock.html index 4981476..c246f0a 100644 --- a/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewExtendedBlock.html +++ b/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewExtendedBlock.html @@ -2,6 +2,7 @@ ==> PARAMETERS - hub: An IndividualMappingHubPage object; the mapping hub page to be previewed {% endcomment %} +{% load wagtailcore_tags %} {% load wagtailimages_tags %}
@@ -17,7 +18,7 @@

- {{hub.external_description_long|safe}} + {{hub.external_description_long|richtext}}

{% include "ui/components/BaseLink.html" with linktext=learn_more_text|add:" "|add:hub.title|add:" "|add:hub_text linkurl=hub.url %} diff --git a/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewProjectsBlock.html b/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewProjectsBlock.html new file mode 100644 index 0000000..dc8b399 --- /dev/null +++ b/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewProjectsBlock.html @@ -0,0 +1,9 @@ +{% comment %} +==> PARAMETERS +- hub: An IndividualMappingHubPage object; the mapping hub page to be previewed +{% endcomment %} +{% load wagtailimages_tags %} + + + {% include "./MappingHubPreviewBlockBase.html" with hub=hub_project.get_parent.specific %} + diff --git a/app/ui/templates/ui/components/misc_panels/LinkBlockWithImage.html b/app/ui/templates/ui/components/misc_panels/LinkBlockWithImage.html index 046bd4f..a4c1df7 100644 --- a/app/ui/templates/ui/components/misc_panels/LinkBlockWithImage.html +++ b/app/ui/templates/ui/components/misc_panels/LinkBlockWithImage.html @@ -5,13 +5,14 @@ - linktext: string; the text to show for the link - linkurl: string; the desired url {% endcomment %} +{% load wagtailcore_tags %} {% load wagtailimages_tags %}

{% image image original class="aspect-[2/1] object-cover" %}

{{title}}

- {{description|safe}} + {{description|richtext}}

{% include "ui/components/BaseLink.html" %} diff --git a/app/ui/templates/ui/components/navigation/FooterNavigation.html b/app/ui/templates/ui/components/navigation/FooterNavigation.html index 2aa3619..e90fc6e 100644 --- a/app/ui/templates/ui/components/navigation/FooterNavigation.html +++ b/app/ui/templates/ui/components/navigation/FooterNavigation.html @@ -4,6 +4,7 @@ {% load homepage_tags %} {% get_home_page as home_page %} {% get_navigation as navigation %} +{% load wagtailcore_tags %} {% load wagtailimages_tags %}

@@ -48,7 +49,7 @@ {% endfor %}
- {{home_page.footer_bottom_copyright|safe}} + {{home_page.footer_bottom_copyright|richtext}}
diff --git a/app/ui/templates/ui/components/news/NewsPreviewBlockProjects.html b/app/ui/templates/ui/components/news/NewsPreviewBlockProjects.html index 8a97511..ede4717 100644 --- a/app/ui/templates/ui/components/news/NewsPreviewBlockProjects.html +++ b/app/ui/templates/ui/components/news/NewsPreviewBlockProjects.html @@ -3,6 +3,7 @@ - news: an IndividualNewsPage object; the news page to be previewed - showimage: optional; if Truthy, the article's image will show up in the preview {% endcomment %} +{% load wagtailcore_tags %} {% load wagtailimages_tags %} {% image news.image original as image_p %} @@ -26,7 +27,7 @@

- {{ news.intro|safe }} + {{ news.intro|richtext }}

diff --git a/app/ui/templates/ui/components/programs/ProgramPreviewBlockBase.html b/app/ui/templates/ui/components/programs/ProgramPreviewBlockBase.html index 5ceab04..b31c423 100644 --- a/app/ui/templates/ui/components/programs/ProgramPreviewBlockBase.html +++ b/app/ui/templates/ui/components/programs/ProgramPreviewBlockBase.html @@ -3,6 +3,7 @@ - program: An IndividualProgramPage object; the program page to be previewed {% endcomment %} +{% load wagtailcore_tags %} {% load wagtailimages_tags %} {% image program.header_image original as image_p %} @@ -13,7 +14,7 @@

{{ program.title }}

- {{ program.subtitle|safe }} + {{ program.subtitle|richtext }}
diff --git a/app/ui/templates/ui/components/sections/BaseSectionWithImage.html b/app/ui/templates/ui/components/sections/BaseSectionWithImage.html index 6234c23..bdf060d 100644 --- a/app/ui/templates/ui/components/sections/BaseSectionWithImage.html +++ b/app/ui/templates/ui/components/sections/BaseSectionWithImage.html @@ -15,6 +15,7 @@ - imageright: if truthy, the image will always be on the right on desktop size - imagenotwide: if truthy, the image will not stretch to the edge of the screen in tablet/mobile sizes {% endcomment %} +{% load wagtailcore_tags %} {% load wagtailimages_tags %}
@@ -22,13 +23,13 @@
- {{title|safe}} + {{title|richtext}}
{% if title_underline %}
{% endif %}
- {{description|safe}} + {{description|richtext}}
{% if button2_text %} diff --git a/app/ui/templates/ui/components/sections/LinkListSection.html b/app/ui/templates/ui/components/sections/LinkListSection.html index 97e2caf..f06fe00 100644 --- a/app/ui/templates/ui/components/sections/LinkListSection.html +++ b/app/ui/templates/ui/components/sections/LinkListSection.html @@ -4,11 +4,12 @@ - description: html element; the description for the section - links: list of link objects; these objects should have a .value.text and a .value.link {% endcomment %} +{% load wagtailcore_tags %}

{{title}}


- {{description|safe}} + {{description|richtext}}
{% for link in links %} diff --git a/app/ui/templates/ui/components/sidebar/SmallSectionWithHeaderAndDivider.html b/app/ui/templates/ui/components/sidebar/SmallSectionWithHeaderAndDivider.html index 7eecea1..7312f94 100644 --- a/app/ui/templates/ui/components/sidebar/SmallSectionWithHeaderAndDivider.html +++ b/app/ui/templates/ui/components/sidebar/SmallSectionWithHeaderAndDivider.html @@ -3,11 +3,12 @@ - header: The text for the header; a string - text: The text for the body; an element. Should be a

element {% endcomment %} +{% load wagtailcore_tags %}

{{ header }}

- {{ text|safe }} + {{ text|richtext }}


diff --git a/home/templates/home/components/CheckOutOpportunitiesSection.html b/home/templates/home/components/CheckOutOpportunitiesSection.html index 1f220cb..3e9f26e 100644 --- a/home/templates/home/components/CheckOutOpportunitiesSection.html +++ b/home/templates/home/components/CheckOutOpportunitiesSection.html @@ -1,5 +1,6 @@ {% load homepage_tags %} {% get_home_page as home_page %} +{% load wagtailcore_tags %} {% load wagtailimages_tags %} {% comment %} OPPORTUNITIES {% endcomment %} @@ -9,10 +10,10 @@
- {{home_page.opportunities_title|safe}} + {{home_page.opportunities_title|richtext}}
- {{home_page.opportunities_description|safe}} + {{home_page.opportunities_description|richtext}}
diff --git a/home/templates/home/components/ImpactAreasPanel.html b/home/templates/home/components/ImpactAreasPanel.html index cf9600e..ea9db17 100644 --- a/home/templates/home/components/ImpactAreasPanel.html +++ b/home/templates/home/components/ImpactAreasPanel.html @@ -1,3 +1,4 @@ +{% load wagtailcore_tags %} {% load wagtailimages_tags %}
{{ area.title }}
- {{ area.description|safe }} + {{ area.description|richtext }}

diff --git a/home/templates/home/components/MappingHubsPanel.html b/home/templates/home/components/MappingHubsPanel.html index bd938df..adb7281 100644 --- a/home/templates/home/components/MappingHubsPanel.html +++ b/home/templates/home/components/MappingHubsPanel.html @@ -1,3 +1,4 @@ +{% load wagtailcore_tags %} {% load wagtailimages_tags %} {% image page.mapping_hubs_background original as image_p %} @@ -10,12 +11,12 @@

- {{ page.mapping_hubs_title|safe }} + {{ page.mapping_hubs_title|richtext }}

{{ hub.title }} @@ -52,7 +53,7 @@

- {{ hub.intro|safe }} + {{ hub.intro|richtext }}
@@ -96,7 +97,7 @@
- {{ hub.intro|safe }} + {{ hub.intro|richtext }}

diff --git a/home/templatetags/homepage_tags.py b/home/templatetags/homepage_tags.py index cf36d38..0f85288 100644 --- a/home/templatetags/homepage_tags.py +++ b/home/templatetags/homepage_tags.py @@ -2,6 +2,7 @@ from django import template from django.utils.translation import get_language from home.models import HomePage +from django.conf import settings register = template.Library() @@ -30,3 +31,8 @@ def get_navigation(context): navigation = current_page.get_ancestors(inclusive=True).type(HomePage).first().specific.navigation return navigation + + +@register.simple_tag +def get_mapbox_key(): + return settings.MAPBOX_ACCESS_TOKEN diff --git a/hot_osm/settings/base.py b/hot_osm/settings/base.py index 4ea4d20..2dd994a 100644 --- a/hot_osm/settings/base.py +++ b/hot_osm/settings/base.py @@ -53,6 +53,7 @@ "app.misc", "app.partners", "app.tech", + "app.our_work", "search", "users", "utils", @@ -81,6 +82,7 @@ "wagtail_localize.locales", "wagtail_modeladmin", "storages", + "wagtailgeowidget", ] MIDDLEWARE = [ @@ -261,4 +263,11 @@ # Any template in BASE_TEMPLATE_NAMES or any template that extends a template in # BASE_TEMPLATE_NAMES is a "page" and will be rendered as-is without being wrapped. "BASE_TEMPLATE_NAMES": ["patterns/base_page.html"], +} + +MAPBOX_ACCESS_TOKEN = os.getenv("MAPBOX_ACCESS_TOKEN") +GEO_WIDGET_LEAFLET_TILE_LAYER = "https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=" + MAPBOX_ACCESS_TOKEN + +GEO_WIDGET_LEAFLET_TILE_LAYER_OPTIONS = { + "attribution": '© Mapbox © OpenStreetMap', } \ No newline at end of file diff --git a/hot_osm/templates/base.html b/hot_osm/templates/base.html index 790dad1..66e0903 100644 --- a/hot_osm/templates/base.html +++ b/hot_osm/templates/base.html @@ -43,6 +43,8 @@ + {% block extra_head %} + {% endblock %}

diff --git a/poetry.lock b/poetry.lock index 429b2da..235ce5b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1511,6 +1511,23 @@ Wagtail = ">=5.2" docs = ["Sphinx (>=6.0)", "myst_parser (>=0.18.1,<1.0)", "pyenchant (>=3.1.1,<4)", "sphinx-autobuild (>=0.6.0)", "sphinx-wagtail-theme (==6.2.0)", "sphinx_copybutton (>=0.5)", "sphinxcontrib-spelling (>=8.0,<9.0)"] testing = ["dj-database-url (>=2.0.0)", "pre-commit (<3.0)"] +[[package]] +name = "wagtailgeowidget" +version = "8.1.1" +description = "Wagtail-Geo-Widget is the complete map solution for your Wagtail site." +optional = false +python-versions = "*" +files = [ + {file = "wagtailgeowidget-8.1.1-py3-none-any.whl", hash = "sha256:30379aaf773762c36d139ababdf239ce77aa6514a1d80cbffcbdb5a495626b0e"}, + {file = "wagtailgeowidget-8.1.1.tar.gz", hash = "sha256:3fbf83da821c787a3dae03885861e96a89e0cf0dd680b0ac158a4d8a55c5e7ec"}, +] + +[package.dependencies] +Wagtail = ">=4.1" + +[package.extras] +test = ["factory-boy", "pytest", "pytest-django"] + [[package]] name = "wagtailmenus" version = "4.0" @@ -1599,4 +1616,4 @@ testing = ["Pillow (>=9.1.0,<11.0.0)", "Wand (>=0.6,<1.0)", "black (==22.3.0)", [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "285a20e6be8789e4fb1192672ffcb57b45e91a88394630a1817c22f69d03bb95" +content-hash = "776b17be304318286f118cf6e4220cb1a41020338da110842179e2af7256b31d" diff --git a/pyproject.toml b/pyproject.toml index 234b610..7b734d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,7 @@ dj-database-url = "^2.2.0" whitenoise = "^6.6.0" django-storages = "^1.14.3" boto3 = "^1.34.129" +wagtailgeowidget = "^8.1.1" [tool.poetry.dev-dependencies]