diff --git a/app/core/migrations/0003_hotsearchablepage.py b/app/core/migrations/0003_hotsearchablepage.py new file mode 100644 index 0000000..bbe934b --- /dev/null +++ b/app/core/migrations/0003_hotsearchablepage.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.7 on 2024-07-08 21:16 + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0089_log_entry_data_json_null_to_object'), + ('core', '0002_alter_partner_partner_logo_alter_partner_partner_url'), + ] + + operations = [ + migrations.CreateModel( + name='HOTSearchablePage', + 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')), + ('intro', wagtail.fields.RichTextField(blank=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + ] diff --git a/app/core/migrations/0004_testpagepage.py b/app/core/migrations/0004_testpagepage.py new file mode 100644 index 0000000..dd1b55a --- /dev/null +++ b/app/core/migrations/0004_testpagepage.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.7 on 2024-07-08 21:31 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0003_hotsearchablepage'), + ] + + operations = [ + migrations.CreateModel( + name='TestPagePage', + fields=[ + ('hotsearchablepage_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='core.hotsearchablepage')), + ], + options={ + 'abstract': False, + }, + bases=('core.hotsearchablepage',), + ), + ] diff --git a/app/core/migrations/0005_remove_hotsearchablepage_intro_delete_testpagepage.py b/app/core/migrations/0005_remove_hotsearchablepage_intro_delete_testpagepage.py new file mode 100644 index 0000000..ee4161d --- /dev/null +++ b/app/core/migrations/0005_remove_hotsearchablepage_intro_delete_testpagepage.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2024-07-08 21:35 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0004_testpagepage'), + ] + + operations = [ + migrations.RemoveField( + model_name='hotsearchablepage', + name='intro', + ), + migrations.DeleteModel( + name='TestPagePage', + ), + ] diff --git a/app/core/migrations/0006_delete_hotsearchablepage.py b/app/core/migrations/0006_delete_hotsearchablepage.py new file mode 100644 index 0000000..052077b --- /dev/null +++ b/app/core/migrations/0006_delete_hotsearchablepage.py @@ -0,0 +1,16 @@ +# Generated by Django 4.2.7 on 2024-07-09 22:09 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0005_remove_hotsearchablepage_intro_delete_testpagepage'), + ] + + operations = [ + migrations.DeleteModel( + name='HOTSearchablePage', + ), + ] diff --git a/app/core/models.py b/app/core/models.py index dc01482..cc04e8e 100644 --- a/app/core/models.py +++ b/app/core/models.py @@ -1,4 +1,6 @@ from django.db import models +from wagtail.models import Page +from wagtail.fields import RichTextField from wagtail.snippets.models import register_snippet from wagtail.admin.panels import FieldPanel, MultiFieldPanel, InlinePanel diff --git a/app/events/migrations/0004_eventownerpage_keyword_search_hint_and_more.py b/app/events/migrations/0004_eventownerpage_keyword_search_hint_and_more.py new file mode 100644 index 0000000..634a82e --- /dev/null +++ b/app/events/migrations/0004_eventownerpage_keyword_search_hint_and_more.py @@ -0,0 +1,48 @@ +# Generated by Django 4.2.7 on 2024-06-27 18:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('events', '0003_eventownerpage_event_read_more_text_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='eventownerpage', + name='keyword_search_hint', + field=models.CharField(default='Search by keyword'), + ), + migrations.AddField( + model_name='eventownerpage', + name='results_text', + field=models.CharField(default='Results'), + ), + migrations.AddField( + model_name='eventownerpage', + name='search_button_text', + field=models.CharField(default='Search'), + ), + migrations.AddField( + model_name='eventownerpage', + name='sort_by_new', + field=models.CharField(default='Sort by New'), + ), + migrations.AddField( + model_name='eventownerpage', + name='sort_by_old', + field=models.CharField(default='Sort by Old'), + ), + migrations.AddField( + model_name='eventownerpage', + name='sort_by_titlea', + field=models.CharField(default='Sort by Title Alphabetical'), + ), + migrations.AddField( + model_name='eventownerpage', + name='sort_by_titlez', + field=models.CharField(default='Sort by Title Reverse Alphabetical'), + ), + ] diff --git a/app/events/models.py b/app/events/models.py index 47a1d1c..7acc034 100644 --- a/app/events/models.py +++ b/app/events/models.py @@ -1,15 +1,56 @@ from django.db import models +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 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 wagtail.search import index class EventOwnerPage(Page): + def get_context(self, request, *args, **kwargs): + context = super().get_context(request, *args, **kwargs) + + keyword = request.GET.get('keyword', '') + events_list = IndividualEventPage.objects.live().filter(locale=context['page'].locale) + + if keyword: + events_list = events_list.search(keyword).get_queryset() + + match request.GET.get('sort', ''): + case 'sort.new': + events_list = events_list.order_by('-start_date_time') + case 'sort.old': + events_list = events_list.order_by('start_date_time') + case 'sort.titlea': + events_list = events_list.order_by('title') + case 'sort.titlez': + events_list = events_list.order_by('-title') + case _: + events_list = events_list.order_by('-start_date_time') + + page = request.GET.get('page', 1) + paginator = Paginator(events_list, 6) # if you want more/less items per page (i.e., per load), change the number here to something else + try: + events = paginator.page(page) + except PageNotAnInteger: + events = paginator.page(1) + except EmptyPage: + events = paginator.page(paginator.num_pages) + + context['events'] = events + context['events_paginator'] = paginator + context['current_page'] = int(page) + return context + max_count = 1 + subpage_types = [ + 'events.IndividualEventPage' + ] + event_location_title = models.CharField(default="Event Location") join_event_title = models.CharField(default="Join This Event") rsvp_button_text = models.CharField(default="RSVP") @@ -18,20 +59,39 @@ class EventOwnerPage(Page): view_all_events_url = models.URLField(blank=True) event_read_more_text = models.CharField(default="Read more") + keyword_search_hint = models.CharField(default="Search by keyword") + sort_by_new = models.CharField(default="Sort by New") + sort_by_old = models.CharField(default="Sort by Old") + sort_by_titlea = models.CharField(default="Sort by Title Alphabetical") + sort_by_titlez = models.CharField(default="Sort by Title Reverse Alphabetical") + search_button_text = models.CharField(default="Search") + results_text = models.CharField(default="Results") + content_panels = Page.content_panels + [ - FieldPanel('event_location_title'), - FieldPanel('join_event_title'), - FieldPanel('rsvp_button_text'), - FieldPanel('more_events_title'), - FieldPanel('view_all_events_text'), - FieldPanel('view_all_events_url'), - FieldPanel('event_read_more_text'), + MultiFieldPanel([ + FieldPanel('keyword_search_hint'), + FieldPanel('sort_by_new'), + FieldPanel('sort_by_old'), + FieldPanel('sort_by_titlea'), + FieldPanel('sort_by_titlez'), + FieldPanel('search_button_text'), + FieldPanel('results_text'), + ], heading="Event Search Page"), + MultiFieldPanel([ + FieldPanel('event_location_title'), + FieldPanel('join_event_title'), + FieldPanel('rsvp_button_text'), + FieldPanel('more_events_title'), + FieldPanel('view_all_events_text'), + FieldPanel('view_all_events_url'), + FieldPanel('event_read_more_text'), + ], heading="Individual Event Page"), ] class IndividualEventPage(Page): - parent_page_type = [ - 'projects.ProjectOwnerPage' + parent_page_types = [ + 'events.EventOwnerPage' ] start_date_time = models.DateTimeField() @@ -60,6 +120,12 @@ class IndividualEventPage(Page): ('event', PageChooserBlock(page_type="events.IndividualEventPage")) ], use_json_field=True, null=True, blank=True) + search_fields = Page.search_fields + [ + index.SearchField('title'), + index.SearchField('intro'), + index.SearchField('search_description'), + ] + content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel('start_date_time'), diff --git a/app/events/templates/events/components/EventsSortOption.html b/app/events/templates/events/components/EventsSortOption.html new file mode 100644 index 0000000..d364b07 --- /dev/null +++ b/app/events/templates/events/components/EventsSortOption.html @@ -0,0 +1,4 @@ +
+ + +
\ No newline at end of file diff --git a/app/events/templates/events/event_owner_page.html b/app/events/templates/events/event_owner_page.html new file mode 100644 index 0000000..1d067b5 --- /dev/null +++ b/app/events/templates/events/event_owner_page.html @@ -0,0 +1,59 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-eventownerpage{% endblock %} +{% block extra_css %} + {% compress css %} + {% endcompress css %} +{% endblock extra_css %} + +{% block content %} +
+
+

{{page.title}}

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

+ {{page.sort_by_new}} +

+ {% include "ui/components/icon_svgs/LinkCaret.html" with class="rotate-90 text-hot-red" %} +
+
+
+ {% include "./components/EventsSortOption.html" with sort_by=page.sort_by_new sort_id="sort.new" %} + {% include "./components/EventsSortOption.html" with sort_by=page.sort_by_old sort_id="sort.old" %} + {% include "./components/EventsSortOption.html" with sort_by=page.sort_by_titlea sort_id="sort.titlea" %} + {% include "./components/EventsSortOption.html" with sort_by=page.sort_by_titlez sort_id="sort.titlez" %} +
+
+ +
+ +
+
+
+ + {% comment %} EVENT ITEMS {% endcomment %} +

{{events_paginator.count}} {{page.results_text}}

+
+ {% for event in events %} + {% include "ui/components/events/EventPreviewBlockEvent.html" with event=event showimage=True %} + {% endfor %} +
+ + {% comment %} PAGE NAVIGATION {% endcomment %} + {% include "ui/components/utilities/PaginatorNavigation.html" with paginator=events_paginator current_page=current_page %} +
+
+{% endblock %} diff --git a/app/get_involved/__init__.py b/app/get_involved/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/get_involved/admin.py b/app/get_involved/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/app/get_involved/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/app/get_involved/apps.py b/app/get_involved/apps.py new file mode 100644 index 0000000..49f491e --- /dev/null +++ b/app/get_involved/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class GetInvolvedConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'app.get_involved' diff --git a/app/get_involved/migrations/0001_initial.py b/app/get_involved/migrations/0001_initial.py new file mode 100644 index 0000000..7a8ff1a --- /dev/null +++ b/app/get_involved/migrations/0001_initial.py @@ -0,0 +1,26 @@ +# Generated by Django 4.2.7 on 2024-07-03 18:17 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('wagtailcore', '0089_log_entry_data_json_null_to_object'), + ] + + operations = [ + migrations.CreateModel( + name='GetInvolvedPage', + 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')), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + ] diff --git a/app/get_involved/migrations/0002_getinvolvedpage_black_box_link_text_and_more.py b/app/get_involved/migrations/0002_getinvolvedpage_black_box_link_text_and_more.py new file mode 100644 index 0000000..b32523d --- /dev/null +++ b/app/get_involved/migrations/0002_getinvolvedpage_black_box_link_text_and_more.py @@ -0,0 +1,133 @@ +# Generated by Django 4.2.7 on 2024-07-03 19:30 + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailimages', '0025_alter_image_file_alter_rendition_file'), + ('get_involved', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='getinvolvedpage', + name='black_box_link_text', + field=models.CharField(default='Contact Us'), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='black_box_link_url', + field=models.URLField(blank=True, null=True), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='black_box_title', + field=models.CharField(default='Stay in Touch'), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='dogear_box_link_text', + field=models.CharField(default='Contact by Country'), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='dogear_box_link_url', + field=models.URLField(blank=True), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='dogear_box_title', + field=models.CharField(default='Connect with our OSM community!'), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='events', + field=wagtail.fields.StreamField([('event', wagtail.blocks.PageChooserBlock(page_type=['events.IndividualEventPage']))], blank=True, null=True, use_json_field=True), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='events_title', + field=models.CharField(default='Events'), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='get_involved_community_title', + field=models.CharField(default='Get Involved in Our Community'), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='get_involved_large_panels', + field=wagtail.fields.StreamField([('panel', wagtail.blocks.StructBlock([('image', wagtail.images.blocks.ImageChooserBlock()), ('title', wagtail.blocks.CharBlock()), ('description', wagtail.blocks.RichTextBlock()), ('link_text', wagtail.blocks.CharBlock()), ('link_url', wagtail.blocks.URLBlock(required=False))]))], blank=True, null=True, use_json_field=True), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='header_image', + field=models.ForeignKey(blank=True, help_text='Header image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image'), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='join_us_panels', + field=wagtail.fields.StreamField([('panel', wagtail.blocks.StructBlock([('image', wagtail.images.blocks.ImageChooserBlock()), ('page', wagtail.blocks.PageChooserBlock())]))], blank=True, null=True, use_json_field=True), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='join_us_title', + field=models.CharField(default='Join Us'), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='partner_with_us_button_link', + field=models.URLField(blank=True), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='partner_with_us_button_text', + field=models.CharField(default='Partner With Us'), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='partner_with_us_description', + field=wagtail.fields.RichTextField(blank=True), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='partner_with_us_image', + field=models.ForeignKey(blank=True, help_text='Header image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image'), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='partner_with_us_title', + field=models.CharField(default='Partner With Us!'), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='red_box_link_text', + field=models.CharField(default='Donate Today'), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='red_box_link_url', + field=models.URLField(blank=True, null=True), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='red_box_title', + field=models.CharField(default="Support HOT's work!"), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='view_all_events_link', + field=models.URLField(blank=True), + ), + migrations.AddField( + model_name='getinvolvedpage', + name='view_all_events_text', + field=models.CharField(default='View all Events'), + ), + ] diff --git a/app/get_involved/migrations/0003_getinvolvedpage_join_us_panel_read_more_and_more.py b/app/get_involved/migrations/0003_getinvolvedpage_join_us_panel_read_more_and_more.py new file mode 100644 index 0000000..f362606 --- /dev/null +++ b/app/get_involved/migrations/0003_getinvolvedpage_join_us_panel_read_more_and_more.py @@ -0,0 +1,26 @@ +# Generated by Django 4.2.7 on 2024-07-03 23:20 + +from django.db import migrations, models +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks + + +class Migration(migrations.Migration): + + dependencies = [ + ('get_involved', '0002_getinvolvedpage_black_box_link_text_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='getinvolvedpage', + name='join_us_panel_read_more', + field=models.CharField(default='Read More'), + ), + migrations.AlterField( + model_name='getinvolvedpage', + name='join_us_panels', + field=wagtail.fields.StreamField([('panel', wagtail.blocks.StructBlock([('image', wagtail.images.blocks.ImageChooserBlock()), ('page', wagtail.blocks.PageChooserBlock()), ('tablet_description', wagtail.blocks.RichTextBlock(blank=True, required=False))]))], blank=True, null=True, use_json_field=True), + ), + ] diff --git a/app/get_involved/migrations/__init__.py b/app/get_involved/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/get_involved/models.py b/app/get_involved/models.py new file mode 100644 index 0000000..2cb2356 --- /dev/null +++ b/app/get_involved/models.py @@ -0,0 +1,101 @@ +from django.db import models + +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 wagtail.images.blocks import ImageChooserBlock +from modelcluster.fields import ParentalKey, ParentalManyToManyField + + +class GetInvolvedLargePanel(StructBlock): + image = ImageChooserBlock() + title = CharBlock() + description = RichTextBlock() + link_text = CharBlock() + link_url = URLBlock(required=False) + + +class JoinUsPanel(StructBlock): + image = ImageChooserBlock() + page = PageChooserBlock() + tablet_description = RichTextBlock(required=False, blank=True) + + +class GetInvolvedPage(Page): + max_count = 1 + + header_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Header image" + ) + + partner_with_us_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Header image" + ) + partner_with_us_title = models.CharField(default="Partner With Us!") + partner_with_us_description = RichTextField(blank=True) + partner_with_us_button_text = models.CharField(default="Partner With Us") + partner_with_us_button_link = models.URLField(blank=True) + + get_involved_community_title = models.CharField(default="Get Involved in Our Community") + get_involved_large_panels = StreamField([('panel', GetInvolvedLargePanel())], use_json_field=True, blank=True, null=True) + dogear_box_title = models.CharField(default="Connect with our OSM community!") + dogear_box_link_text = models.CharField(default="Contact by Country") + dogear_box_link_url = models.URLField(blank=True) + events_title = models.CharField(default="Events") + view_all_events_text = models.CharField(default="View all Events") + view_all_events_link = models.URLField(blank=True) + events = StreamField([('event', PageChooserBlock(page_type="events.IndividualEventPage"))], use_json_field=True, null=True, blank=True, max_num=3) + + join_us_title = models.CharField(default="Join Us") + join_us_panels = StreamField([('panel', JoinUsPanel())], use_json_field=True, blank=True, null=True) + join_us_panel_read_more = models.CharField(default="Read More") + red_box_title = models.CharField(default="Support HOT's work!") + red_box_link_text = models.CharField(default="Donate Today") + red_box_link_url = models.URLField(null=True, blank=True) + black_box_title = models.CharField(default="Stay in Touch") + black_box_link_text = models.CharField(default="Contact Us") + black_box_link_url = models.URLField(null=True, blank=True) + + content_panels = Page.content_panels + [ + FieldPanel('header_image'), + MultiFieldPanel([ + FieldPanel('partner_with_us_image'), + FieldPanel('partner_with_us_title'), + FieldPanel('partner_with_us_description'), + FieldPanel('partner_with_us_button_text'), + FieldPanel('partner_with_us_button_link'), + ], heading="Partner With Us"), + MultiFieldPanel([ + FieldPanel('get_involved_community_title'), + FieldPanel('get_involved_large_panels'), + FieldPanel('dogear_box_title'), + FieldPanel('dogear_box_link_text'), + FieldPanel('dogear_box_link_url'), + FieldPanel('events_title'), + FieldPanel('view_all_events_text'), + FieldPanel('view_all_events_link'), + FieldPanel('events'), + ], heading="Get Involved in Our Community"), + MultiFieldPanel([ + FieldPanel('join_us_title'), + FieldPanel('join_us_panels'), + FieldPanel('join_us_panel_read_more'), + FieldPanel('red_box_title'), + FieldPanel('red_box_link_text'), + FieldPanel('red_box_link_url'), + FieldPanel('black_box_title'), + FieldPanel('black_box_link_text'), + FieldPanel('black_box_link_url'), + ], heading="Bottom Area"), + ] diff --git a/app/get_involved/templates/get_involved/get_involved_page.html b/app/get_involved/templates/get_involved/get_involved_page.html new file mode 100644 index 0000000..7343149 --- /dev/null +++ b/app/get_involved/templates/get_involved/get_involved_page.html @@ -0,0 +1,62 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-getinvolvedpage{% endblock %} +{% block extra_css %} + {% compress css %} + {% endcompress css %} +{% endblock extra_css %} + +{% block content %} + {% include "ui/components/BasePageHeader.html" with title=page.title image=page.header_image %} +
+ {% include "ui/components/sections/BaseSectionWithImage.html" with title=page.partner_with_us_title image=page.partner_with_us_image imageright=True title_underline=True red_button=True button_text=page.partner_with_us_button_text button_link=page.partner_with_us_button_link description=page.partner_with_us_description imagenotwide=True imagebottom=True%} +
+ +
+
+
+ {% include "ui/components/TitleWithUnderline.html" with title=page.get_involved_community_title %} +
+ {% for panel in page.get_involved_large_panels %} + {% include "ui/components/misc_panels/LinkBlockWithImage.html" with title=panel.value.title image=panel.value.image description=panel.value.description linktext=panel.value.link_text linkurl=panel.value.link_url %} + {% endfor %} +
+ +
+ {% include "ui/components/dogear_boxes/DogearAnyColourLong.html" with title=page.dogear_box_title linktext=page.dogear_box_link_text linkurl=page.dogear_box_link_url textcolour="black" colour="var(--hot-light-grey)" arrowcolour="black" %} +
+ + {% include "ui/components/FlexTitleWithLink.html" with title=page.events_title linktext=page.view_all_events_text linkurl=page.view_all_events_link class="my-4" %} +
+ {% for event in page.events %} + {% include "ui/components/events/EventPreviewBlockEvent.html" with event=event.value showimage=True %} + {% endfor %} +
+
+
+
+ +
+
+ {% include "ui/components/TitleWithUnderline.html" with title=page.join_us_title %} + +
+ {% for panel in page.join_us_panels %} + {% include "ui/components/misc_panels/PagePreviewWithTabletDescription.html" with image=panel.value.image page=panel.value.page tablet_description=panel.value.tablet_description read_more_text=page.join_us_panel_read_more %} + {% 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_url %} +
+
+ {% include "ui/components/dogear_boxes/DogearBlack.html" with title=page.black_box_title linktext=page.black_box_link_text linkurl=page.black_box_link_url %} +
+
+
+
+{% endblock %} diff --git a/app/get_involved/tests.py b/app/get_involved/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/app/get_involved/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/app/get_involved/views.py b/app/get_involved/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/app/get_involved/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/app/impact_areas/migrations/0015_alter_individualimpactareapage_external_icon.py b/app/impact_areas/migrations/0015_alter_individualimpactareapage_external_icon.py new file mode 100644 index 0000000..1a9ed94 --- /dev/null +++ b/app/impact_areas/migrations/0015_alter_individualimpactareapage_external_icon.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2024-06-28 23:12 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailimages', '0025_alter_image_file_alter_rendition_file'), + ('impact_areas', '0014_remove_individualimpactareapage_black_dogear_box_link_text_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='individualimpactareapage', + name='external_icon', + field=models.ForeignKey(blank=True, help_text='The icon representing this page which is shown for previews of this page on other pages. This should be a purely black image which is ideally as wide as it is tall.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image'), + ), + ] diff --git a/app/impact_areas/models.py b/app/impact_areas/models.py index d63017a..4410a28 100644 --- a/app/impact_areas/models.py +++ b/app/impact_areas/models.py @@ -42,7 +42,7 @@ def get_context(self, request, *args, **kwargs): context['other_impact_areas'] = other_impact_areas return context - parent_page_type = [ + parent_page_types = [ 'impact_areas.ImpactAreasPage' ] @@ -62,7 +62,7 @@ def get_context(self, request, *args, **kwargs): blank=True, on_delete=models.SET_NULL, related_name="+", - help_text="The icon representing this page which is shown for previews of this page on other pages." + help_text="The icon representing this page which is shown for previews of this page on other pages. This should be a purely black image which is ideally as wide as it is tall." ) intro_image = models.ForeignKey( "wagtailimages.Image", @@ -108,6 +108,10 @@ class ImpactAreaBlock(StreamBlock): class ImpactAreasPage(Page): max_count = 1 + subpage_types = [ + 'impact_areas.IndividualImpactAreaPage' + ] + intro = RichTextField(blank=True) image = models.ForeignKey( diff --git a/app/impact_areas/templates/impact_areas/impact_areas_page.html b/app/impact_areas/templates/impact_areas/impact_areas_page.html index c5867f9..b406d8e 100644 --- a/app/impact_areas/templates/impact_areas/impact_areas_page.html +++ b/app/impact_areas/templates/impact_areas/impact_areas_page.html @@ -13,8 +13,8 @@ {% include "ui/components/BasePageHeader.html" with title=page.title intro=page.intro image=page.image %}
- {% for block in page.impact_area_blocks %} - {% include "ui/components/LearnMoreAboutBlurbWithImage.html" with title=block.value.title description=block.value.description image=block.value.image link=block.value.link %} + {% for child in page.get_children %} + {% include "ui/components/impact_areas/ImpactAreaPreviewBlock.html" with ia=child.specific %} {% endfor %}
{% endblock %} \ No newline at end of file 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 3a971b0..6ed0220 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 @@ -43,7 +43,7 @@ {% include "ui/components/BaseLink.html" with linktext=page.get_parent.specific.view_all_projects_text linkurl=page.view_all_projects_link %}

-
+
{% for project in projects %} {% include "ui/components/projects/ProjectPreviewBlockNews.html" with project=project showimage=True %} {% endfor %} diff --git a/app/mapping_hubs/migrations/0009_openmappinghubspage.py b/app/mapping_hubs/migrations/0009_openmappinghubspage.py new file mode 100644 index 0000000..0da2ebf --- /dev/null +++ b/app/mapping_hubs/migrations/0009_openmappinghubspage.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.7 on 2024-07-02 18:58 + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0089_log_entry_data_json_null_to_object'), + ('mapping_hubs', '0008_alter_individualmappinghubpage_dogear_boxes'), + ] + + operations = [ + migrations.CreateModel( + name='OpenMappingHubsPage', + 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')), + ('banner_description', wagtail.fields.RichTextField(blank=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + ] diff --git a/app/mapping_hubs/migrations/0010_rename_banner_description_openmappinghubspage_header_description_and_more.py b/app/mapping_hubs/migrations/0010_rename_banner_description_openmappinghubspage_header_description_and_more.py new file mode 100644 index 0000000..765e9f6 --- /dev/null +++ b/app/mapping_hubs/migrations/0010_rename_banner_description_openmappinghubspage_header_description_and_more.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.7 on 2024-07-02 19:10 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailimages', '0025_alter_image_file_alter_rendition_file'), + ('mapping_hubs', '0009_openmappinghubspage'), + ] + + operations = [ + migrations.RenameField( + model_name='openmappinghubspage', + old_name='banner_description', + new_name='header_description', + ), + migrations.AddField( + model_name='openmappinghubspage', + name='header_image', + field=models.ForeignKey(blank=True, help_text='Header image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image'), + ), + ] diff --git a/app/mapping_hubs/migrations/0011_openmappinghubspage_hub_text_and_more.py b/app/mapping_hubs/migrations/0011_openmappinghubspage_hub_text_and_more.py new file mode 100644 index 0000000..d70c35b --- /dev/null +++ b/app/mapping_hubs/migrations/0011_openmappinghubspage_hub_text_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.7 on 2024-07-02 21:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mapping_hubs', '0010_rename_banner_description_openmappinghubspage_header_description_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='openmappinghubspage', + name='hub_text', + field=models.CharField(default='Hub', help_text="The text following a hub's name; i.e., if this field is 'Hub', the title for 'Asia-Pacific' would become 'Asia-Pacific Hub'."), + ), + migrations.AddField( + model_name='openmappinghubspage', + name='learn_more_text', + field=models.CharField(default='Learn More about', help_text="The text preceeding the hub's name in the link text; i.e., if this field is 'Learn More about', the link text for 'Asia-Pacific Hub' would become 'Learn More about Asia-Pacific Hub'."), + ), + ] diff --git a/app/mapping_hubs/migrations/0012_mappinghubprojectspage.py b/app/mapping_hubs/migrations/0012_mappinghubprojectspage.py new file mode 100644 index 0000000..fca3cc1 --- /dev/null +++ b/app/mapping_hubs/migrations/0012_mappinghubprojectspage.py @@ -0,0 +1,33 @@ +# Generated by Django 4.2.7 on 2024-07-04 22:41 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0089_log_entry_data_json_null_to_object'), + ('mapping_hubs', '0011_openmappinghubspage_hub_text_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='MappingHubProjectsPage', + 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')), + ('load_more_projects_text', models.CharField(default='Load More Projects')), + ('projects_by_hub_title', models.CharField(default='See Projects by Open Mapping Hub')), + ('red_box_title', models.CharField(default='Start Mapping')), + ('red_box_link_text', models.CharField(default='Start Mapping')), + ('red_box_link_url', models.URLField(blank=True, null=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_url', models.URLField(blank=True, null=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + ] diff --git a/app/mapping_hubs/migrations/0013_alter_mappinghubprojectspage_black_box_link_text_and_more.py b/app/mapping_hubs/migrations/0013_alter_mappinghubprojectspage_black_box_link_text_and_more.py new file mode 100644 index 0000000..929575f --- /dev/null +++ b/app/mapping_hubs/migrations/0013_alter_mappinghubprojectspage_black_box_link_text_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 4.2.7 on 2024-07-04 23:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mapping_hubs', '0012_mappinghubprojectspage'), + ] + + operations = [ + migrations.AlterField( + model_name='mappinghubprojectspage', + name='black_box_link_text', + field=models.CharField(default='Get involved'), + ), + migrations.AlterField( + model_name='mappinghubprojectspage', + name='black_box_title', + field=models.CharField(default='See the many ways to get involved with HOT and open mapping'), + ), + migrations.AlterField( + model_name='mappinghubprojectspage', + name='red_box_link_text', + field=models.CharField(default='Explore projects'), + ), + migrations.AlterField( + model_name='mappinghubprojectspage', + name='red_box_title', + field=models.CharField(default="See all of HOT's projects"), + ), + ] diff --git a/app/mapping_hubs/models.py b/app/mapping_hubs/models.py index b2e6256..1f79b86 100644 --- a/app/mapping_hubs/models.py +++ b/app/mapping_hubs/models.py @@ -1,5 +1,6 @@ from django import forms from django.db import models +from django.db.models import Q from wagtail.models import Page from wagtail.fields import RichTextField, StreamField @@ -30,10 +31,82 @@ class DogearBoxBlock(StreamBlock): blocks = DogearBoxStructBlock() +class MappingHubProjectsPage(Page): + def get_context(self, request): + context = super().get_context(request) + + parent_hub = context['page'].get_parent() + + projects = IndividualProjectPage.objects.live().filter( + Q(region_hub_list__contains=[{'type': 'region_hub', 'value': parent_hub.id}]) + ).filter(locale=context['page'].locale) + + other_hubs_projects = MappingHubProjectsPage.objects.live().filter(locale=context['page'].locale) + + context['projects'] = projects + context['other_hubs'] = other_hubs_projects + return context + + parent_page_types = [ + 'mapping_hubs.IndividualMappingHubPage' + ] + + load_more_projects_text = models.CharField(default="Load More Projects") + + projects_by_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_url = models.URLField(null=True, blank=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_url = models.URLField(null=True, blank=True) + + content_panels = Page.content_panels + [ + FieldPanel('load_more_projects_text'), + FieldPanel('projects_by_hub_title'), + FieldPanel('red_box_title'), + FieldPanel('red_box_link_text'), + FieldPanel('red_box_link_url'), + FieldPanel('black_box_title'), + FieldPanel('black_box_link_text'), + FieldPanel('black_box_link_url'), + ] + + +class OpenMappingHubsPage(Page): + max_count = 1 + + subpage_types = [ + 'mapping_hubs.IndividualMappingHubPage' + ] + + header_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Header image", + ) + header_description = RichTextField(blank=True) + hub_text = models.CharField(default="Hub", help_text="The text following a hub's name; i.e., if this field is 'Hub', the title for 'Asia-Pacific' would become 'Asia-Pacific Hub'.") + learn_more_text = models.CharField(default="Learn More about", help_text="The text preceeding the hub's name in the link text; i.e., if this field is 'Learn More about', the link text for 'Asia-Pacific Hub' would become 'Learn More about Asia-Pacific Hub'.") + + content_panels = Page.content_panels + [ + FieldPanel('header_image'), + FieldPanel('header_description'), + FieldPanel('hub_text'), + FieldPanel('learn_more_text'), + ] + + class IndividualMappingHubPage(Page): def get_context(self, request): context = super().get_context(request) - projects = IndividualProjectPage.objects.filter(owner_region_hub=context['page'], locale=context['page'].locale) + projects = IndividualProjectPage.objects.live().filter( + Q(region_hub_list__contains=[{'type': 'region_hub', 'value': context['page'].id}]) + ).filter(locale=context['page'].locale) context['projects'] = projects other_hubs = IndividualMappingHubPage.objects.live().filter(locale=context['page'].locale) context['other_hubs'] = other_hubs diff --git a/app/mapping_hubs/templates/mapping_hubs/components/projects_header.html b/app/mapping_hubs/templates/mapping_hubs/components/projects_header.html new file mode 100644 index 0000000..72d8327 --- /dev/null +++ b/app/mapping_hubs/templates/mapping_hubs/components/projects_header.html @@ -0,0 +1,25 @@ +{% comment %} +==> PARAMETERS +- body: The content of the header +- image: A Wagtail image +{% endcomment %} + +{% load wagtailimages_tags %} + +{% image page.get_parent.specific.header_image original as image_p %} +
+
+
+
+
+

+ {{ page.get_parent.specific.header_hub_text_white }} {{ page.get_parent.specific.header_hub_text_red }} +

+

+ {{ page.get_parent.specific.project_section_title }} +

+
+
+
+
+
diff --git a/app/mapping_hubs/templates/mapping_hubs/individual_mapping_hub_page.html b/app/mapping_hubs/templates/mapping_hubs/individual_mapping_hub_page.html index 833a3b1..7e20464 100644 --- a/app/mapping_hubs/templates/mapping_hubs/individual_mapping_hub_page.html +++ b/app/mapping_hubs/templates/mapping_hubs/individual_mapping_hub_page.html @@ -35,7 +35,7 @@
{% for project in projects %} - {% include "ui/components/projects/ProjectPreviewBlockMapHub.html" with project=project showimage="True" %} + {% include "ui/components/projects/ProjectPreviewBlockMapHub.html" with project=project.specific showimage="True" %} {% endfor %}
diff --git a/app/mapping_hubs/templates/mapping_hubs/mapping_hub_projects_page.html b/app/mapping_hubs/templates/mapping_hubs/mapping_hub_projects_page.html new file mode 100644 index 0000000..40b6eba --- /dev/null +++ b/app/mapping_hubs/templates/mapping_hubs/mapping_hub_projects_page.html @@ -0,0 +1,61 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-mappinghubprojectspage{% endblock %} +{% block extra_css %} + {% compress css %} + {% endcompress css %} +{% endblock extra_css %} + +{% block content %} + {% include "./components/projects_header.html" %} +
+
+
+ {% for project in projects %} + {% include "ui/components/projects/ProjectPreviewBlockNews.html" with project=project.specific showimage=True %} + {% endfor %} +
+

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

+ +

+ {{page.projects_by_hub_title}} +

+
+ {% for hub in other_hubs %} + {% if hub != page %} + + {% include "ui/components/mapping_hub/MappingHubPreviewBlockBase.html" with hub=hub.get_parent.specific %} + + {% endif %} + {% 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_url %} +
+
+ {% include "ui/components/dogear_boxes/DogearBlack.html" with title=page.black_box_title linktext=page.black_box_link_text linkurl=page.black_box_link_url %} +
+
+
+
+{% endblock %} diff --git a/app/mapping_hubs/templates/mapping_hubs/open_mapping_hubs_page.html b/app/mapping_hubs/templates/mapping_hubs/open_mapping_hubs_page.html new file mode 100644 index 0000000..42a07e1 --- /dev/null +++ b/app/mapping_hubs/templates/mapping_hubs/open_mapping_hubs_page.html @@ -0,0 +1,26 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-openmappinghubspage{% endblock %} +{% block extra_css %} + {% compress css %} + {% endcompress css %} +{% endblock extra_css %} + +{% block content %} + {% include "ui/components/BasePageHeader.html" with title=page.title image=page.header_image intro=page.header_description %} + +
+
+
+ {% for child in page.get_children %} + {% include "ui/components/mapping_hub/MappingHubPreviewExtendedBlock.html" with hub=child.specific hub_text=page.hub_text learn_more_text=page.learn_more_text %} + {% endfor %} +
+
+
+ + {% include "home/components/CheckOutOpportunitiesSection.html" %} +{% endblock %} diff --git a/app/members/migrations/0003_rename_introduction_individualmemberpage_intro.py b/app/members/migrations/0003_rename_introduction_individualmemberpage_intro.py new file mode 100644 index 0000000..3dc041a --- /dev/null +++ b/app/members/migrations/0003_rename_introduction_individualmemberpage_intro.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-07-08 23:24 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0002_remove_individualmemberpage_location_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='individualmemberpage', + old_name='introduction', + new_name='intro', + ), + ] diff --git a/app/members/migrations/0004_membergroupownerpage_membergrouppage.py b/app/members/migrations/0004_membergroupownerpage_membergrouppage.py new file mode 100644 index 0000000..9cb5a03 --- /dev/null +++ b/app/members/migrations/0004_membergroupownerpage_membergrouppage.py @@ -0,0 +1,52 @@ +# Generated by Django 4.2.7 on 2024-07-09 21:59 + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0089_log_entry_data_json_null_to_object'), + ('wagtailimages', '0025_alter_image_file_alter_rendition_file'), + ('members', '0003_rename_introduction_individualmemberpage_intro'), + ] + + operations = [ + migrations.CreateModel( + name='MemberGroupOwnerPage', + 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')), + ('search_placeholder', models.CharField(default='Search by name')), + ('filter_by_country', models.CharField(default='Filter by Country')), + ('sort_by_titlea', models.CharField(default='Sort by Title Alphabetical')), + ('sort_by_titlez', models.CharField(default='Sort by Title Reverse Alphabetical')), + ('load_more_text', models.CharField(default='Load more', help_text="This will be a prefix to the title of the page; i.e., if the page title is 'Voting members', and this field is 'Load more', this will end up appearing as 'Load more Voting members'.")), + ('footer_box_title', models.CharField(default='Work for HOT')), + ('footer_box_description', wagtail.fields.RichTextField(blank=True)), + ('footer_box_button_text', models.CharField(default='Check our Job Opportunities')), + ('footer_box_button_link', models.URLField(blank=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='MemberGroupPage', + 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')), + ('intro', wagtail.fields.RichTextField(blank=True, help_text='Appears in the header.')), + ('body_intro', wagtail.fields.RichTextField(blank=True)), + ('body_description', wagtail.fields.RichTextField(blank=True)), + ('desktop_size_items_per_row', models.SmallIntegerField(default=6, help_text='The number of members shown per row on desktop sizes.', validators=[django.core.validators.MinValueValidator(4), django.core.validators.MaxValueValidator(8)])), + ('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/members/migrations/0005_individualmemberpage_member_groups.py b/app/members/migrations/0005_individualmemberpage_member_groups.py new file mode 100644 index 0000000..e151dc3 --- /dev/null +++ b/app/members/migrations/0005_individualmemberpage_member_groups.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2024-07-09 22:14 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0004_membergroupownerpage_membergrouppage'), + ] + + operations = [ + migrations.AddField( + model_name='individualmemberpage', + name='member_groups', + field=wagtail.fields.StreamField([('member_group', wagtail.blocks.PageChooserBlock(page_type=['members.MemberGroupPage']))], blank=True, null=True, use_json_field=True), + ), + ] diff --git a/app/members/migrations/0006_alter_individualmemberpage_member_groups.py b/app/members/migrations/0006_alter_individualmemberpage_member_groups.py new file mode 100644 index 0000000..a981794 --- /dev/null +++ b/app/members/migrations/0006_alter_individualmemberpage_member_groups.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2024-07-09 22:45 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0005_individualmemberpage_member_groups'), + ] + + operations = [ + migrations.AlterField( + model_name='individualmemberpage', + name='member_groups', + field=wagtail.fields.StreamField([('member_group', wagtail.blocks.StructBlock([('group', wagtail.blocks.PageChooserBlock(page_type=['members.MemberGroupPage'])), ('role', wagtail.blocks.CharBlock())]))], blank=True, null=True, use_json_field=True), + ), + ] diff --git a/app/members/migrations/0007_alter_individualmemberpage_member_groups.py b/app/members/migrations/0007_alter_individualmemberpage_member_groups.py new file mode 100644 index 0000000..14c8004 --- /dev/null +++ b/app/members/migrations/0007_alter_individualmemberpage_member_groups.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2024-07-09 22:48 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0006_alter_individualmemberpage_member_groups'), + ] + + operations = [ + migrations.AlterField( + model_name='individualmemberpage', + name='member_groups', + field=wagtail.fields.StreamField([('member_group', wagtail.blocks.StructBlock([('group', wagtail.blocks.PageChooserBlock(page_type=['members.MemberGroupPage'])), ('role', wagtail.blocks.CharBlock(required=False))]))], blank=True, null=True, use_json_field=True), + ), + ] diff --git a/app/members/migrations/0008_membergrouppage_hub_shown_and_more.py b/app/members/migrations/0008_membergrouppage_hub_shown_and_more.py new file mode 100644 index 0000000..b032e78 --- /dev/null +++ b/app/members/migrations/0008_membergrouppage_hub_shown_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.7 on 2024-07-09 23:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0007_alter_individualmemberpage_member_groups'), + ] + + operations = [ + migrations.AddField( + model_name='membergrouppage', + name='hub_shown', + field=models.BooleanField(blank=True, default=False, null=True), + ), + migrations.AddField( + model_name='membergrouppage', + name='position_shown', + field=models.BooleanField(blank=True, default=False, null=True), + ), + ] diff --git a/app/members/migrations/0009_alter_membergrouppage_hub_shown_and_more.py b/app/members/migrations/0009_alter_membergrouppage_hub_shown_and_more.py new file mode 100644 index 0000000..06f523c --- /dev/null +++ b/app/members/migrations/0009_alter_membergrouppage_hub_shown_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.7 on 2024-07-09 23:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0008_membergrouppage_hub_shown_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='membergrouppage', + name='hub_shown', + field=models.BooleanField(default=False), + ), + migrations.AlterField( + model_name='membergrouppage', + name='position_shown', + field=models.BooleanField(default=False), + ), + ] diff --git a/app/members/migrations/0010_membergrouppage_show_search_options.py b/app/members/migrations/0010_membergrouppage_show_search_options.py new file mode 100644 index 0000000..d3c5861 --- /dev/null +++ b/app/members/migrations/0010_membergrouppage_show_search_options.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-07-10 17:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0009_alter_membergrouppage_hub_shown_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='membergrouppage', + name='show_search_options', + field=models.BooleanField(default=True), + ), + ] diff --git a/app/members/migrations/0011_membergroupownerpage_search_button_text.py b/app/members/migrations/0011_membergroupownerpage_search_button_text.py new file mode 100644 index 0000000..60de3dc --- /dev/null +++ b/app/members/migrations/0011_membergroupownerpage_search_button_text.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-07-10 17:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0010_membergrouppage_show_search_options'), + ] + + operations = [ + migrations.AddField( + model_name='membergroupownerpage', + name='search_button_text', + field=models.CharField(default='Search'), + ), + ] diff --git a/app/members/migrations/0012_membergroupownerpage_view_all_text.py b/app/members/migrations/0012_membergroupownerpage_view_all_text.py new file mode 100644 index 0000000..f1c7235 --- /dev/null +++ b/app/members/migrations/0012_membergroupownerpage_view_all_text.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-07-10 19:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0011_membergroupownerpage_search_button_text'), + ] + + operations = [ + migrations.AddField( + model_name='membergroupownerpage', + name='view_all_text', + field=models.CharField(default='View all'), + ), + ] diff --git a/app/members/models.py b/app/members/models.py index 00e53fe..7121960 100644 --- a/app/members/models.py +++ b/app/members/models.py @@ -1,11 +1,15 @@ from django.db import models +from django.core.validators import MinValueValidator, MaxValueValidator from wagtail.admin.panels import FieldPanel, MultiFieldPanel from wagtail.blocks import CharBlock, StreamBlock, StructBlock, URLBlock, PageChooserBlock from wagtail.fields import RichTextField, StreamField from wagtail.models import Page from django.db.models import Q +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from app.projects.models import IndividualProjectPage from app.news.models import IndividualNewsPage +from app.mapping_hubs.models import IndividualMappingHubPage +from wagtail.search import index class WebLinkStructBlock(StructBlock): link_text = CharBlock(required=True) @@ -16,6 +20,127 @@ class WebLinkBlock(StreamBlock): blocks = WebLinkStructBlock() +class MemberGroupOwnerPage(Page): + max_count = 1 + + subpage_types = [ + 'members.MemberGroupPage' + ] + + search_placeholder = models.CharField(default="Search by name") + filter_by_country = models.CharField(default="Filter by Country") + sort_by_titlea = models.CharField(default="Sort by Name Alphabetical") + sort_by_titlez = models.CharField(default="Sort by Name Reverse Alphabetical") + search_button_text = models.CharField(default="Search") + + load_more_text = models.CharField(default="Load more", help_text="This will be a prefix to the title of the page; i.e., if the page title is 'Voting members', and this field is 'Load more', this will end up appearing as 'Load more Voting members'.") + + view_all_text = models.CharField(default="View all") + + footer_box_title = models.CharField(default="Work for HOT") + footer_box_description = RichTextField(blank=True) + footer_box_button_text = models.CharField(default="Check our Job Opportunities") + footer_box_button_link = models.URLField(blank=True) + + content_panels = Page.content_panels + [ + MultiFieldPanel([ + FieldPanel('search_placeholder'), + FieldPanel('filter_by_country'), + FieldPanel('sort_by_titlea'), + FieldPanel('sort_by_titlez'), + FieldPanel('search_button_text'), + ], heading="Search options"), + FieldPanel('load_more_text'), + FieldPanel('view_all_text'), + MultiFieldPanel([ + FieldPanel('footer_box_title'), + FieldPanel('footer_box_description'), + FieldPanel('footer_box_button_text'), + FieldPanel('footer_box_button_link'), + ], heading="Footer box"), + ] + + +class MemberGroupPage(Page): + def get_context(self, request, *args, **kwargs): + context = super().get_context(request, *args, **kwargs) + + members = IndividualMemberPage.objects.live().filter( + Q(member_groups__contains=[{'type': 'member_group', 'value': { 'group': context['page'].id }}]) + ).filter(locale=context['page'].locale) + + keyword = request.GET.get('keyword', '') + + if keyword: + members = members.search(keyword).get_queryset() + + hubs = IndividualMappingHubPage.objects.live().filter(locale=context['page'].locale) + query = Q() + for hub in hubs: + if request.GET.get(str(hub), ''): + query = query | Q(location_hub=hub) + members = members.filter(query).distinct() + + match request.GET.get('sort', ''): + case 'sort.titlea': + members = members.order_by('title') + case 'sort.titlez': + members = members.order_by('-title') + case _: + members = members.order_by('title') + + page = request.GET.get('page', 1) + paginator = Paginator(members, 12) # if you want more/less items per page (i.e., per load), change the number here to something else + try: + members = paginator.page(page) + except PageNotAnInteger: + members = paginator.page(1) + except EmptyPage: + members = paginator.page(paginator.num_pages) + + context['members'] = members + context['hubs'] = hubs + context['groups'] = MemberGroupPage.objects.live().filter(locale=context['page'].locale).exclude(id=context['page'].id) + + return context + + parent_page_type = [ + 'members.MemberGroupOwnerPage' + ] + + header_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Header image" + ) + intro = RichTextField(blank=True, help_text="Appears in the header.") + + body_intro = RichTextField(blank=True) + body_description = RichTextField(blank=True) + + show_search_options = models.BooleanField(default=True) + desktop_size_items_per_row = models.SmallIntegerField(default=6, help_text="The number of members shown per row on desktop sizes.", validators=[ + MinValueValidator(4), + MaxValueValidator(8), + ]) + position_shown = models.BooleanField(default=False) + hub_shown = models.BooleanField(default=False) + + content_panels = Page.content_panels + [ + FieldPanel('header_image'), + FieldPanel('intro'), + FieldPanel('body_intro'), + FieldPanel('body_description'), + FieldPanel('show_search_options'), + FieldPanel('desktop_size_items_per_row'), + FieldPanel('position_shown'), + FieldPanel('hub_shown'), + ] + + class MemberOwnerPage(Page): max_count = 1 @@ -29,6 +154,12 @@ class MemberOwnerPage(Page): FieldPanel('project_contribution_title'), ] + +class MemberGroupBlock(StructBlock): + group = PageChooserBlock(page_type="members.MemberGroupPage") + role = CharBlock(required=False) + + """ This page should only be created as a child of a MemberOwnerPage! Its template depends on fields from the MemberOwnerPage in order @@ -62,6 +193,7 @@ def get_context(self, request, *args, **kwargs): related_name="+", help_text="An image of the member", ) + member_groups = StreamField([('member_group', MemberGroupBlock())], use_json_field=True, null=True, blank=True) position = models.CharField() location_hub = models.ForeignKey( 'mapping_hubs.IndividualMappingHubPage', @@ -70,13 +202,20 @@ def get_context(self, request, *args, **kwargs): on_delete=models.SET_NULL, related_name='+' ) - introduction = RichTextField() + intro = RichTextField() on_the_web_links = StreamField(WebLinkBlock(), blank=True, use_json_field=True) + + search_fields = Page.search_fields + [ + index.SearchField('title'), + index.SearchField('search_description'), + index.SearchField('intro'), + ] content_panels = Page.content_panels + [ FieldPanel('image'), + FieldPanel('member_groups'), FieldPanel('position'), FieldPanel('location_hub'), - FieldPanel('introduction'), + FieldPanel('intro'), FieldPanel('on_the_web_links'), ] diff --git a/app/members/templates/members/components/MembersSortOption.html b/app/members/templates/members/components/MembersSortOption.html new file mode 100644 index 0000000..8e3320f --- /dev/null +++ b/app/members/templates/members/components/MembersSortOption.html @@ -0,0 +1,4 @@ +
+ + +
\ No newline at end of file diff --git a/app/members/templates/members/components/TailwindGridSizeAssurance.html b/app/members/templates/members/components/TailwindGridSizeAssurance.html new file mode 100644 index 0000000..09e7b65 --- /dev/null +++ b/app/members/templates/members/components/TailwindGridSizeAssurance.html @@ -0,0 +1,9 @@ +{% comment %} + +This file is just for making sure that the member_group_page's grid columns work right! +This ensures that all possible values for the grid column field will have its Tailwind +class built. + +{% endcomment %} +
+
\ No newline at end of file diff --git a/app/members/templates/members/individual_member_page.html b/app/members/templates/members/individual_member_page.html index ccd2c59..c090bfe 100644 --- a/app/members/templates/members/individual_member_page.html +++ b/app/members/templates/members/individual_member_page.html @@ -3,7 +3,7 @@ {% load wagtailcore_tags %} {% load wagtailimages_tags %} {% load compress %} -{% block body_class %}template-individualmappinghubpage{% endblock %} +{% block body_class %}template-individualmemberpage{% endblock %} {% block extra_css %} {% compress css %} {% endcompress css %} @@ -19,14 +19,14 @@ {% endif %}
- {% comment %} TODO: REMOVE PLACEHOLDER AND IMPLEMENT PROPER (BASICALLY REQUIRES OTHER PAGES COMPLETION) {% endcomment %} -

- Board - / - Voting Member - / - Staff -

+ {% if page.member_groups %} +

+ {% for group in page.member_groups %} + {{group.value.role}} + {% if not forloop.last %} / {% endif %} + {% endfor %} +

+ {% endif %}

{{page.title}}

{{page.position}} @@ -34,14 +34,14 @@

{{page.title}}

{{page.location_hub.title}}

- {{page.introduction|safe}} + {{page.intro|safe}}
{% comment %} ON THE WEB LINKS {% endcomment %} {% if page.on_the_web_links %} -
+

{{page.get_parent.specific.on_the_web_title}}

diff --git a/app/members/templates/members/member_group_page.html b/app/members/templates/members/member_group_page.html new file mode 100644 index 0000000..3910f80 --- /dev/null +++ b/app/members/templates/members/member_group_page.html @@ -0,0 +1,116 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-membergrouppage{% endblock %} +{% block extra_css %} + {% compress css %} + {% endcompress css %} +{% endblock extra_css %} + +{% block content %} + {% include "ui/components/PageHeaderWithBlur.html" with title=page.title subtitle=page.intro image=page.header_image %} + +
+
+
+ {{page.body_intro|safe}} +
+
+ {{page.body_description|safe}} +
+
+ + {% if page.show_search_options %} +
+
+ {% comment %} KEYWORD SEARCH {% endcomment %} +
+ + {% include "ui/components/icon_svgs/SearchIcon.html" with class="text-hot-red mx-3" %} +
+ + {% comment %} COUNTRY {% endcomment %} +
+
+

+ {{page.get_parent.specific.filter_by_country}} +

+ {% include "ui/components/icon_svgs/LinkCaret.html" with class="rotate-90 text-hot-red" %} +
+
+
+ {% for hub in hubs %} +
+ + +
+ {% endfor %} +
+
+ + {% comment %} SORT {% endcomment %} +
+
+

+ {{page.get_parent.specific.sort_by_titlea}} +

+ {% include "ui/components/icon_svgs/LinkCaret.html" with class="rotate-90 text-hot-red" %} +
+
+
+ {% include "./components/MembersSortOption.html" with sort_by=page.get_parent.specific.sort_by_titlea sort_id="sort.titlea" %} + {% include "./components/MembersSortOption.html" with sort_by=page.get_parent.specific.sort_by_titlez sort_id="sort.titlez" %} +
+
+ +
+ +
+
+
+ {% endif %} + + {% comment %} MEMBERS LIST {% endcomment %} +
+ {% for member in members %} + {% include "ui/components/members/MemberPreviewBlock.html" with member=member position_shown=page.position_shown hub_shown=page.hub_shown %} + {% endfor %} +
+

+ {% if members.has_next %} + {% comment %} {% endcomment %} + + {% endif %} +

+ + {% comment %} BOTTOM AREA {% endcomment %} +
+ {% for group in groups %} + {% if forloop.counter0|divisibleby:2 %} +
+ {% include "ui/components/dogear_boxes/DogearRed.html" with title=group.title linktext=page.get_parent.specific.view_all_text|add:' '|add:group.title linkurl=group.url %} +
+ {% else %} +
+ {% include "ui/components/dogear_boxes/DogearBlack.html" with title=group.title linktext=page.get_parent.specific.view_all_text|add:' '|add:group.title linkurl=group.url %} +
+ {% endif %} + {% endfor %} +
+
+ {% include "ui/components/FooterBannerWithTextAndLink.html" with text=page.get_parent.specific.footer_box_title url=page.get_parent.specific.footer_box_button_link buttontext=page.get_parent.specific.footer_box_button_text description=page.get_parent.specific.footer_box_description %} +
+
+{% endblock %} diff --git a/app/news/models.py b/app/news/models.py index 279dda1..c0887ae 100644 --- a/app/news/models.py +++ b/app/news/models.py @@ -21,6 +21,9 @@ def get_context(self, request, *args, **kwargs): keyword = request.GET.get('keyword', '') news_list = IndividualNewsPage.objects.live().filter(locale=context['page'].locale) + + if keyword: + news_list = news_list.search(keyword).get_queryset() categories = NewsCategory.objects.all() tags = [x[4:] for x in request.GET.keys() if x.startswith("tag.")] @@ -28,24 +31,24 @@ def get_context(self, request, *args, **kwargs): for category in categories: if request.GET.get(str(category), ''): query = query | Q(categories=category) + news_list = news_list.filter(query).distinct() + + query = Q() for tag in tags: query = query | Q(tags__name=tag) news_list = news_list.filter(query).distinct() match request.GET.get('sort', ''): case 'sort.new': - news_list = news_list.order_by('date') - case 'sort.old': news_list = news_list.order_by('-date') + case 'sort.old': + news_list = news_list.order_by('date') case 'sort.titlea': news_list = news_list.order_by('title') case 'sort.titlez': news_list = news_list.order_by('-title') case _: - news_list = news_list.order_by('date') - - if keyword: - news_list = news_list.search(keyword) + news_list = news_list.order_by('-date') page = request.GET.get('page', 1) paginator = Paginator(news_list, 6) # if you want more/less items per page (i.e., per load), change the number here to something else @@ -64,6 +67,10 @@ def get_context(self, request, *args, **kwargs): max_count = 1 + subpage_types = [ + 'news.IndividualNewsPage' + ] + authors_posted_by_text = models.CharField(default="Posted by", help_text="The text which appears prior to the authors names; with 'posted by', the text displays as 'posted by [author]'.") authors_posted_on_text = models.CharField(default="on", help_text="The text which appears prior to the date; with 'on', it would display as 'on [date]'.") related_projects_title = models.CharField(default="Related Projects") @@ -180,8 +187,9 @@ class IndividualNewsPage(Page): search_fields = Page.search_fields + [ index.SearchField('title'), index.SearchField('intro'), - index.FilterField('newscategory_id'), # the console warns you about this but if you don't have this then category search doesn't work - index.FilterField('name'), + # index.FilterField('newscategory_id'), # the console warns you about this but if you don't have this then category search doesn't work + # index.FilterField('name'), + index.SearchField('search_description'), ] content_panels = Page.content_panels + [ diff --git a/app/news/templates/news/components/NewsSortOption.html b/app/news/templates/news/components/NewsSortOption.html index 8b30d23..d364b07 100644 --- a/app/news/templates/news/components/NewsSortOption.html +++ b/app/news/templates/news/components/NewsSortOption.html @@ -1,4 +1,4 @@
- +
\ No newline at end of file diff --git a/app/news/templates/news/individual_news_page.html b/app/news/templates/news/individual_news_page.html index 26b25ac..c91346e 100644 --- a/app/news/templates/news/individual_news_page.html +++ b/app/news/templates/news/individual_news_page.html @@ -17,7 +17,7 @@

{{ page.title }}

{{page.get_parent.specific.authors_posted_by_text}} {% for author in page.authors %} - {{author.value.title}} + {{author.value.title}} {% if not forloop.last %} , {% endif %} @@ -41,70 +41,70 @@

{{ page.title }}

{% comment %} SIDEBAR {% endcomment %}
{% if page.related_projects%} -
-
-

- {{ page.get_parent.specific.related_projects_title }} -

-
- {% with projects=page.related_projects %} - {% for project in projects %} - {% include "ui/components/projects/ProjectPreviewBlockNews.html" with project=project.value %} - {% endfor %} - {% endwith %} +
+
+

+ {{ page.get_parent.specific.related_projects_title }} +

+
+ {% with projects=page.related_projects %} + {% for project in projects %} + {% include "ui/components/projects/ProjectPreviewBlockNews.html" with project=project.value %} + {% endfor %} + {% endwith %} +
-
{% endif %} {% if page.related_news %} -
-
-

- {{ page.get_parent.specific.related_news_title }} -

-
- {% include "ui/components/BaseLink.html" with linkurl="#" linktext=page.get_parent.specific.view_all_news_text %} -
-
- {% with allnews=page.related_news %} - {% for news in allnews %} - {% include "ui/components/news/NewsPreviewBlockNews.html" with news=news.value readmoretext=page.get_parent.specific.read_more_text %} - {% endfor %} - {% endwith %} +
+
+

+ {{ page.get_parent.specific.related_news_title }} +

+
+ {% include "ui/components/BaseLink.html" with linkurl="#" linktext=page.get_parent.specific.view_all_news_text %} +
+
+ {% with allnews=page.related_news %} + {% for news in allnews %} + {% include "ui/components/news/NewsPreviewBlockNews.html" with news=news.value readmoretext=page.get_parent.specific.read_more_text %} + {% endfor %} + {% endwith %} +
-
{% endif %} {% if page.categories.all %} -
-
-

- {{ page.get_parent.specific.categories_title }} -

-

- {% with categories=page.categories.all %} - {% for category in categories %} - {{ category.category_name }}{% if not forloop.last %}, {% endif %} - {% endfor %} - {% endwith %} -

-
+
+
+

+ {{ page.get_parent.specific.categories_title }} +

+

+ {% with categories=page.categories.all %} + {% for category in categories %} + {{ category.category_name }}{% if not forloop.last %}, {% endif %} + {% endfor %} + {% endwith %} +

+
{% endif %} {% if page.tags.all %} -
-
-

- {{ page.get_parent.specific.tags_title }} -

-

- {% with tags=page.tags.all %} - {% for tag in tags %} - {{ tag }}{% if not forloop.last %}, {% endif %} - {% endfor %} - {% endwith %} -

-
+
+
+

+ {{ page.get_parent.specific.tags_title }} +

+

+ {% with tags=page.tags.all %} + {% for tag in tags %} + {{ tag }}{% if not forloop.last %}, {% endif %} + {% endfor %} + {% endwith %} +

+
{% endif %}
diff --git a/app/news/templates/news/news_owner_page.html b/app/news/templates/news/news_owner_page.html index 90b6592..e1e4d9d 100644 --- a/app/news/templates/news/news_owner_page.html +++ b/app/news/templates/news/news_owner_page.html @@ -3,7 +3,7 @@ {% load wagtailcore_tags %} {% load wagtailimages_tags %} {% load compress %} -{% block body_class %}template-individualnewspage{% endblock %} +{% block body_class %}template-newsownerpage{% endblock %} {% block extra_css %} {% compress css %} {% endcompress css %} @@ -94,53 +94,16 @@

{{page.title}}

+ {% comment %} NEWS ITEMS {% endcomment %}

{{news_paginator.count}} {{page.results_text}}

-
+
{% for article in news %} {% include "ui/components/news/NewsPreviewBlockProjects.html" with news=article showimage=True class="[&_.image-hide-small]:hidden md:[&_.image-hide-small]:block" %} {% endfor %}
-
- -

- {% include "ui/components/icon_svgs/LinkCaret.html" with class="rotate-180" %} -

-
-
- {% with ''|center:news_paginator.num_pages as range %} - {% for _ in range %} - {% if forloop.counter == 1 or forloop.counter == news_paginator.num_pages or forloop.counter == current_page or forloop.counter|add:1 == current_page or forloop.counter|add:'-1' == current_page %} - -

- {{forloop.counter}} -

-
- {% endif %} - {% if forloop.counter|add:2 == current_page or forloop.counter|add:'-2' == current_page and not forloop.last %} - {% comment %} - for reasons that i can't begin to comprehend, the if statement - below CANNOT be part of the if statement above. it just does - not work - {% endcomment %} - {% if not forloop.first %} -

...

- {% endif %} - {% endif %} - {% endfor %} - {% endwith %} -
- -

- {% include "ui/components/icon_svgs/LinkCaret.html" %} -

-
-
+ {% comment %} PAGE NAVIGATION {% endcomment %} + {% include "ui/components/utilities/PaginatorNavigation.html" with paginator=news_paginator current_page=current_page %}
{% endblock %} diff --git a/app/programs/models.py b/app/programs/models.py index 9e55079..701c7f5 100644 --- a/app/programs/models.py +++ b/app/programs/models.py @@ -8,6 +8,7 @@ from wagtail.images.blocks import ImageChooserBlock from wagtail.blocks import CharBlock, StreamBlock, StructBlock, URLBlock, RichTextBlock, PageChooserBlock from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register +from wagtail.search import index from app.projects.models import IndividualProjectPage @@ -35,6 +36,10 @@ class ProgramGoalBlock(StreamBlock): class ProgramOwnerPage(Page): max_count = 1 + + subpage_types = [ + 'programs.IndividualProgramPage' + ] stats_title = models.CharField(default="Stats") goals_title = models.CharField(default="Goals") @@ -118,6 +123,12 @@ def get_context(self, request): ('program_page', PageChooserBlock(page_type="programs.IndividualProgramPage")) ], use_json_field=True, null=True, blank=True) + search_fields = Page.search_fields + [ + index.SearchField('title'), + index.SearchField('search_description'), + index.SearchField('intro'), + ] + content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel("subtitle"), diff --git a/app/projects/migrations/0022_projectownerpage_load_more_projects_text.py b/app/projects/migrations/0022_projectownerpage_load_more_projects_text.py new file mode 100644 index 0000000..71a0e62 --- /dev/null +++ b/app/projects/migrations/0022_projectownerpage_load_more_projects_text.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-06-27 22:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0021_individualprojectpage_related_events'), + ] + + operations = [ + migrations.AddField( + model_name='projectownerpage', + name='load_more_projects_text', + field=models.CharField(default='Load More Projects'), + ), + ] diff --git a/app/projects/migrations/0023_remove_individualprojectpage_owner_region_hub.py b/app/projects/migrations/0023_remove_individualprojectpage_owner_region_hub.py new file mode 100644 index 0000000..af8ea42 --- /dev/null +++ b/app/projects/migrations/0023_remove_individualprojectpage_owner_region_hub.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.7 on 2024-06-27 23:06 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0022_projectownerpage_load_more_projects_text'), + ] + + operations = [ + migrations.RemoveField( + model_name='individualprojectpage', + name='owner_region_hub', + ), + ] diff --git a/app/projects/migrations/0024_individualprojectpage_region_hub_list.py b/app/projects/migrations/0024_individualprojectpage_region_hub_list.py new file mode 100644 index 0000000..e1e2261 --- /dev/null +++ b/app/projects/migrations/0024_individualprojectpage_region_hub_list.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2024-07-04 18:38 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0023_remove_individualprojectpage_owner_region_hub'), + ] + + operations = [ + migrations.AddField( + model_name='individualprojectpage', + name='region_hub_list', + field=wagtail.fields.StreamField([('region_hub', wagtail.blocks.PageChooserBlock(page_type=['mapping_hubs.IndividualMappingHubPage']))], blank=True, null=True, use_json_field=True), + ), + ] diff --git a/app/projects/migrations/0025_projectownerpage_header_image.py b/app/projects/migrations/0025_projectownerpage_header_image.py new file mode 100644 index 0000000..15e07d8 --- /dev/null +++ b/app/projects/migrations/0025_projectownerpage_header_image.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2024-07-04 23:02 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailimages', '0025_alter_image_file_alter_rendition_file'), + ('projects', '0024_individualprojectpage_region_hub_list'), + ] + + operations = [ + migrations.AddField( + model_name='projectownerpage', + name='header_image', + field=models.ForeignKey(blank=True, help_text='Header image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image'), + ), + ] diff --git a/app/projects/migrations/0026_remove_individualprojectpage_intro.py b/app/projects/migrations/0026_remove_individualprojectpage_intro.py new file mode 100644 index 0000000..3b3452b --- /dev/null +++ b/app/projects/migrations/0026_remove_individualprojectpage_intro.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.7 on 2024-07-08 21:32 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0025_projectownerpage_header_image'), + ] + + operations = [ + migrations.RemoveField( + model_name='individualprojectpage', + name='intro', + ), + ] diff --git a/app/projects/migrations/0027_individualprojectpage_intro.py b/app/projects/migrations/0027_individualprojectpage_intro.py new file mode 100644 index 0000000..aa40dcd --- /dev/null +++ b/app/projects/migrations/0027_individualprojectpage_intro.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.7 on 2024-07-08 21:32 + +from django.db import migrations +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0026_remove_individualprojectpage_intro'), + ] + + operations = [ + migrations.AddField( + model_name='individualprojectpage', + name='intro', + field=wagtail.fields.RichTextField(blank=True), + ), + ] diff --git a/app/projects/models.py b/app/projects/models.py index 70c6c75..ea22cf0 100644 --- a/app/projects/models.py +++ b/app/projects/models.py @@ -1,16 +1,54 @@ from django import forms from django.db import models +from django.db.models import Q +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 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 wagtail.search import index from modelcluster.fields import ParentalKey, ParentalManyToManyField +""" +This page should only be created as a child of an IndividualMappingHubPage! +Its template depends on fields from the IndividualMappingHubPage in order +to create one unifying place where unchanging fields may be modified. +""" class ProjectOwnerPage(Page): - max_count = 1 + def get_context(self, request, *args, **kwargs): + context = super().get_context(request, *args, **kwargs) + + projects_list = context['page'].get_children().filter(locale=context['page'].locale) + 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) + context['projects'] = projects + return context + max_count = 1 + + subpage_types = [ + 'projects.IndividualProjectPage' + ] + + header_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Header image" + ) + + load_more_projects_text = models.CharField(default="Load More Projects") + impact_areas_title = models.CharField(default="Impact Areas") region_hub_title = models.CharField(default="Region Hub") duration_title = models.CharField(default="Duration") @@ -34,29 +72,35 @@ class ProjectOwnerPage(Page): content_panels = Page.content_panels + [ MultiFieldPanel([ - FieldPanel('impact_areas_title'), - FieldPanel('region_hub_title'), - FieldPanel('duration_title'), - FieldPanel('partners_title'), - FieldPanel('tools_title'), - FieldPanel('contact_title'), - MultiFieldPanel([ - FieldPanel('related_news_title'), - FieldPanel('view_all_news_text'), - FieldPanel('view_all_news_url'), - FieldPanel('related_events_title'), - FieldPanel('view_all_events_text'), - FieldPanel('view_all_events_url'), - ], heading="Related Pages"), - ], heading="Sidebar"), + FieldPanel('header_image'), + FieldPanel('load_more_projects_text'), + ], heading="Project Page"), MultiFieldPanel([ - FieldPanel('red_box_title'), - FieldPanel('red_box_link_text'), - FieldPanel('red_box_link_url'), - FieldPanel('black_box_title'), - FieldPanel('black_box_link_text'), - FieldPanel('black_box_link_url'), - ], heading="Footer"), + MultiFieldPanel([ + FieldPanel('impact_areas_title'), + FieldPanel('region_hub_title'), + FieldPanel('duration_title'), + FieldPanel('partners_title'), + FieldPanel('tools_title'), + FieldPanel('contact_title'), + MultiFieldPanel([ + FieldPanel('related_news_title'), + FieldPanel('view_all_news_text'), + FieldPanel('view_all_news_url'), + FieldPanel('related_events_title'), + FieldPanel('view_all_events_text'), + FieldPanel('view_all_events_url'), + ], heading="Related Pages"), + ], heading="Sidebar"), + MultiFieldPanel([ + FieldPanel('red_box_title'), + FieldPanel('red_box_link_text'), + FieldPanel('red_box_link_url'), + FieldPanel('black_box_title'), + FieldPanel('black_box_link_text'), + FieldPanel('black_box_link_url'), + ], heading="Footer"), + ], heading="Individual Project Page"), ] @@ -66,9 +110,10 @@ class ProjectOwnerPage(Page): to create one unifying place where unchanging fields may be modified. """ class IndividualProjectPage(Page): - parent_page_type = [ + parent_page_types = [ 'projects.ProjectOwnerPage' ] + # > HEADER owner_program = models.ForeignKey( 'wagtailcore.Page', @@ -103,14 +148,8 @@ class IndividualProjectPage(Page): # > SIDE BAR impact_area_list = StreamField([('impact_area', PageChooserBlock(page_type="impact_areas.IndividualImpactAreaPage"))], use_json_field=True, null=True, blank=True) - owner_region_hub = models.ForeignKey( - 'wagtailcore.Page', - null=True, - blank=True, - on_delete=models.SET_NULL, - related_name='+' - ) - + 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) @@ -129,6 +168,12 @@ class IndividualProjectPage(Page): project_contributors = StreamField([('contributor', PageChooserBlock(page_type="members.IndividualMemberPage"))], use_json_field=True, null=True, blank=True) + search_fields = Page.search_fields + [ + index.SearchField('title'), + index.SearchField('search_description'), + index.SearchField('intro'), + ] + content_panels = Page.content_panels + [ MultiFieldPanel([ PageChooserPanel('owner_program', 'programs.IndividualProgramPage'), @@ -147,7 +192,7 @@ class IndividualProjectPage(Page): ], heading="Body"), MultiFieldPanel([ FieldPanel('impact_area_list'), - PageChooserPanel('owner_region_hub', 'mapping_hubs.IndividualMappingHubPage'), + FieldPanel('region_hub_list'), FieldPanel('duration'), FieldPanel('partners_list', widget=forms.CheckboxSelectMultiple), FieldPanel('tools'), diff --git a/app/projects/templates/projects/individual_project_page.html b/app/projects/templates/projects/individual_project_page.html index 630b04d..1db1a43 100644 --- a/app/projects/templates/projects/individual_project_page.html +++ b/app/projects/templates/projects/individual_project_page.html @@ -37,7 +37,9 @@

{{page.get_parent.specific.region_hub_title}}

-

{{page.owner_region_hub.title}}

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

{{hub.value.title}}

+ {% endfor %}

{{page.get_parent.specific.duration_title}}

@@ -68,7 +70,7 @@

{% include "ui/components/BaseLink.html" with linkurl=page.get_parent.specific.view_all_news_url linktext=page.get_parent.specific.view_all_news_text %}
-
+
{% with allnews=page.related_news %} {% for news in allnews %} {% include "ui/components/news/NewsPreviewBlockProjects.html" with news=news.value %} diff --git a/app/projects/templates/projects/project_owner_page.html b/app/projects/templates/projects/project_owner_page.html new file mode 100644 index 0000000..f110ee2 --- /dev/null +++ b/app/projects/templates/projects/project_owner_page.html @@ -0,0 +1,39 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-projectownerpage{% endblock %} +{% block extra_css %} + {% compress css %} + {% endcompress css %} +{% endblock extra_css %} + +{% block content %} + {% include "ui/components/BasePageHeader.html" with title=page.title image=page.header_image %} +
+
+
+ {% for project in projects %} + {% include "ui/components/projects/ProjectPreviewBlockNews.html" with project=project.specific showimage=True %} + {% endfor %} +
+

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

+
+
+{% endblock %} diff --git a/app/search_page/__init__.py b/app/search_page/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/search_page/admin.py b/app/search_page/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/app/search_page/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/app/search_page/apps.py b/app/search_page/apps.py new file mode 100644 index 0000000..6d87f0a --- /dev/null +++ b/app/search_page/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class SearchPageConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'app.search_page' diff --git a/app/search_page/migrations/0001_initial.py b/app/search_page/migrations/0001_initial.py new file mode 100644 index 0000000..3089437 --- /dev/null +++ b/app/search_page/migrations/0001_initial.py @@ -0,0 +1,26 @@ +# Generated by Django 4.2.7 on 2024-07-08 19:38 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('wagtailcore', '0089_log_entry_data_json_null_to_object'), + ] + + operations = [ + migrations.CreateModel( + name='SearchPage', + 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')), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + ] diff --git a/app/search_page/migrations/0002_searchpage_search_text_midfix_and_more.py b/app/search_page/migrations/0002_searchpage_search_text_midfix_and_more.py new file mode 100644 index 0000000..e60451b --- /dev/null +++ b/app/search_page/migrations/0002_searchpage_search_text_midfix_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.7 on 2024-07-08 20:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('search_page', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='searchpage', + name='search_text_midfix', + field=models.CharField(default='returns'), + ), + migrations.AddField( + model_name='searchpage', + name='search_text_postfix', + field=models.CharField(default='results'), + ), + migrations.AddField( + model_name='searchpage', + name='search_text_prefix', + field=models.CharField(default='Your search for'), + ), + ] diff --git a/app/search_page/migrations/0003_searchpage_no_results_text.py b/app/search_page/migrations/0003_searchpage_no_results_text.py new file mode 100644 index 0000000..5885853 --- /dev/null +++ b/app/search_page/migrations/0003_searchpage_no_results_text.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-07-08 23:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('search_page', '0002_searchpage_search_text_midfix_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='searchpage', + name='no_results_text', + field=models.CharField(default='No matching search results for', help_text='This field is a prefix to the current search result in the event no results are found; i.e., if the search keyword was \'Hello\' and this field is \'No matching result for\', the no-result page would show "No matching result for "Hello""'), + ), + ] diff --git a/app/search_page/migrations/0004_searchpage_no_results_go_back.py b/app/search_page/migrations/0004_searchpage_no_results_go_back.py new file mode 100644 index 0000000..82a570c --- /dev/null +++ b/app/search_page/migrations/0004_searchpage_no_results_go_back.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-07-08 23:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('search_page', '0003_searchpage_no_results_text'), + ] + + operations = [ + migrations.AddField( + model_name='searchpage', + name='no_results_go_back', + field=models.CharField(default='Go Back'), + ), + ] diff --git a/app/search_page/migrations/__init__.py b/app/search_page/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/search_page/models.py b/app/search_page/models.py new file mode 100644 index 0000000..e9ecbbb --- /dev/null +++ b/app/search_page/models.py @@ -0,0 +1,58 @@ +from django.db import models +from django.db.models import Q +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger + +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 + + +class SearchPage(Page): + def get_context(self, request, *args, **kwargs): + context = super().get_context(request, *args, **kwargs) + + keyword = request.GET.get('keyword', '') + results_list = Page.objects.live().filter(locale=context['page'].locale) + + if keyword: + results_list = results_list.search(keyword).get_queryset() + + results_list = results_list.exclude(id__in=[1, 2]) + + page = request.GET.get('page', 1) + paginator = Paginator(results_list, 6) # if you want more/less items per page (i.e., per load), change the number here to something else + try: + results = paginator.page(page) + except PageNotAnInteger: + results = paginator.page(1) + except EmptyPage: + results = paginator.page(paginator.num_pages) + + context['results'] = results + context['results_paginator'] = paginator + context['current_page'] = int(page) + context['keyword'] = keyword + return context + + page_description = "Search results will, by default, attempt to pull from an 'intro' field for the page description; otherwise, it will grab the page's meta search description." + + max_count = 1 + + search_text_prefix = models.CharField(default="Your search for") + search_text_midfix = models.CharField(default="returns") + search_text_postfix = models.CharField(default="results") + + no_results_text = models.CharField(default="No matching search results for", help_text="This field is a prefix to the current search result in the event no results are found; i.e., if the search keyword was 'Hello' and this field is 'No matching result for', the no-result page would show \"No matching result for \"Hello\"\"") + no_results_go_back = models.CharField(default="Go Back") + + content_panels = Page.content_panels + [ + MultiFieldPanel([ + FieldPanel("search_text_prefix"), + FieldPanel("search_text_midfix"), + FieldPanel("search_text_postfix"), + ], heading="Search Result Text", help_text="These combine to make the search result text; i.e., if prefix is 'Your search for', midfix is 'returns', and postfix is 'results', the search result text will be \"Your search for \"example\" returns \"x\" results\""), + FieldPanel('no_results_text'), + FieldPanel('no_results_go_back'), + ] diff --git a/app/search_page/templates/search_page/search_page.html b/app/search_page/templates/search_page/search_page.html new file mode 100644 index 0000000..508ed0e --- /dev/null +++ b/app/search_page/templates/search_page/search_page.html @@ -0,0 +1,60 @@ +{% extends "base.html" %} +{% load static wagtailcore_tags %} +{% block body_class %} + template-searchpage +{% endblock body_class %} +{% block content %} +
+
+
+

+ {% if results %} + {{page.search_text_prefix}} "{{keyword}}" {{page.search_text_midfix}} {{results_paginator.count}} {{page.search_text_postfix}} + {% else %} + {{page.no_results_text}} "{{keyword}}" + {% endif %} +

+
+ {% include "ui/components/navigation/SearchForm.html" %} +
+
+ {% if results %} +
+ {% for result in results %} +
+

{{result.title}}

+ {% if result.get_ancestors|length > 2 %} +

+ {% for ancestor in result.get_ancestors|slice:"2:" %} + {{ancestor.title}} + {% if not forloop.last %} > {% endif %} + {% endfor %} +

+ {% endif %} + + {% if result.specific.intro %} +
+ {{result.specific.intro|safe}} +
+ {% else %} + {% if result.search_description %} +

{{result.search_description}}

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

+ {{result.full_url}} +

+
+ {% endfor %} +
+ {% include "ui/components/utilities/PaginatorNavigation.html" with paginator=results_paginator current_page=current_page %} + + {% else %} +

+ {% include "ui/components/BaseLink.html" with linktext=page.no_results_go_back linkurl="javascript:history.back()" %} +

+ {% endif %} +
+
+{% endblock content %} diff --git a/app/search_page/tests.py b/app/search_page/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/app/search_page/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/app/search_page/views.py b/app/search_page/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/app/search_page/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/app/tools_and_resources/__init__.py b/app/tools_and_resources/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/tools_and_resources/admin.py b/app/tools_and_resources/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/app/tools_and_resources/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/app/tools_and_resources/apps.py b/app/tools_and_resources/apps.py new file mode 100644 index 0000000..236d5fe --- /dev/null +++ b/app/tools_and_resources/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ToolsAndResourcesConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'app.tools_and_resources' diff --git a/app/tools_and_resources/migrations/0001_initial.py b/app/tools_and_resources/migrations/0001_initial.py new file mode 100644 index 0000000..ba742b4 --- /dev/null +++ b/app/tools_and_resources/migrations/0001_initial.py @@ -0,0 +1,52 @@ +# Generated by Django 4.2.7 on 2024-07-04 17:17 + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks + + +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='ToolsAndResourcesPage', + 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')), + ('intro_header', models.CharField(blank=True)), + ('intro', wagtail.fields.RichTextField(blank=True)), + ('description', wagtail.fields.RichTextField(blank=True)), + ('learn_more_data_principles_text', models.CharField(default='Learn about our Data & Principles')), + ('learn_more_data_principles_link', models.URLField(blank=True)), + ('large_panels', wagtail.fields.StreamField([('panel', wagtail.blocks.StructBlock([('image', wagtail.images.blocks.ImageChooserBlock()), ('title', wagtail.blocks.CharBlock()), ('description', wagtail.blocks.RichTextBlock()), ('link_text', wagtail.blocks.CharBlock()), ('link_url', wagtail.blocks.URLBlock(required=False))]))], blank=True, null=True, use_json_field=True)), + ('resource_learning_title', models.CharField(default='Resource and Learning Centre')), + ('resource_learning_description', wagtail.fields.RichTextField(blank=True)), + ('get_connected_button_text', models.CharField(default='Get connect now')), + ('get_connected_button_link', models.URLField(blank=True)), + ('dogear_tech_news_title', models.CharField(blank=True)), + ('dogear_tech_news_link_text', models.CharField(default='View our Tech News')), + ('dogear_tech_news_link_url', models.URLField(blank=True)), + ('red_box_title', models.CharField(default='Start Mapping')), + ('red_box_link_text', models.CharField(default='Start Mapping')), + ('red_box_link_url', models.URLField(blank=True, null=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_url', models.URLField(blank=True, null=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')), + ('intro_image', models.ForeignKey(blank=True, help_text='Intro image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image')), + ('resource_learning_image', models.ForeignKey(blank=True, help_text='Resource and Learning Centre 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/tools_and_resources/migrations/0002_alter_toolsandresourcespage_get_connected_button_text.py b/app/tools_and_resources/migrations/0002_alter_toolsandresourcespage_get_connected_button_text.py new file mode 100644 index 0000000..c974feb --- /dev/null +++ b/app/tools_and_resources/migrations/0002_alter_toolsandresourcespage_get_connected_button_text.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-07-04 18:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tools_and_resources', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='toolsandresourcespage', + name='get_connected_button_text', + field=models.CharField(default='Get connected now'), + ), + ] diff --git a/app/tools_and_resources/migrations/__init__.py b/app/tools_and_resources/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/tools_and_resources/models.py b/app/tools_and_resources/models.py new file mode 100644 index 0000000..75db779 --- /dev/null +++ b/app/tools_and_resources/models.py @@ -0,0 +1,100 @@ +from django.db import models + +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 wagtail.images.blocks import ImageChooserBlock +from modelcluster.fields import ParentalKey, ParentalManyToManyField + + +class LargePanel(StructBlock): + image = ImageChooserBlock() + title = CharBlock() + description = RichTextBlock() + link_text = CharBlock() + link_url = URLBlock(required=False) + + +class ToolsAndResourcesPage(Page): + max_count = 1 + + header_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Header image" + ) + + intro_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Intro image" + ) + intro_header = models.CharField(blank=True) + intro = RichTextField(blank=True) + description = RichTextField(blank=True) + learn_more_data_principles_text = models.CharField(default="Learn about our Data & Principles") + learn_more_data_principles_link = models.URLField(blank=True) + + large_panels = StreamField([('panel', LargePanel())], use_json_field=True, null=True, blank=True) + + resource_learning_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Resource and Learning Centre image" + ) + resource_learning_title = models.CharField(default="Resource and Learning Centre") + resource_learning_description = RichTextField(blank=True) + get_connected_button_text = models.CharField(default="Get connected now") + get_connected_button_link = models.URLField(blank=True) + + dogear_tech_news_title = models.CharField(blank=True) + dogear_tech_news_link_text = models.CharField(default="View our Tech News") + dogear_tech_news_link_url = models.URLField(blank=True) + + red_box_title = models.CharField(default="Start Mapping") + red_box_link_text = models.CharField(default="Start Mapping") + red_box_link_url = models.URLField(null=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_url = models.URLField(null=True, blank=True) + + content_panels = Page.content_panels + [ + FieldPanel('header_image'), + MultiFieldPanel([ + FieldPanel('intro_image'), + FieldPanel('intro_header'), + FieldPanel('intro'), + FieldPanel('description'), + FieldPanel('learn_more_data_principles_text'), + FieldPanel('learn_more_data_principles_link'), + ], heading="Intro"), + FieldPanel('large_panels'), + MultiFieldPanel([ + FieldPanel('resource_learning_image'), + FieldPanel('resource_learning_title'), + FieldPanel('resource_learning_description'), + FieldPanel('get_connected_button_text'), + FieldPanel('get_connected_button_link'), + ], heading="Resource and Learning Centre"), + MultiFieldPanel([ + FieldPanel('dogear_tech_news_title'), + FieldPanel('dogear_tech_news_link_text'), + FieldPanel('dogear_tech_news_link_url'), + FieldPanel('red_box_title'), + FieldPanel('red_box_link_text'), + FieldPanel('red_box_link_url'), + FieldPanel('black_box_title'), + FieldPanel('black_box_link_text'), + FieldPanel('black_box_link_url'), + ], heading="Dogear Boxes"), + ] diff --git a/app/tools_and_resources/templates/tools_and_resources/tools_and_resources_page.html b/app/tools_and_resources/templates/tools_and_resources/tools_and_resources_page.html new file mode 100644 index 0000000..4eff124 --- /dev/null +++ b/app/tools_and_resources/templates/tools_and_resources/tools_and_resources_page.html @@ -0,0 +1,67 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-toolsandresourcespage{% endblock %} +{% block extra_css %} + {% compress css %} + {% endcompress css %} +{% endblock extra_css %} + +{% block content %} + {% include "ui/components/BasePageHeader.html" with title=page.title image=page.header_image %} + +
+
+
+
+

{{page.intro_header}}

+ +
+ {{page.intro|safe}} +
+ +
+ {{page.description|safe}} +
+ + +

+ {{page.learn_more_data_principles_text}} + {% include "ui/components/icon_svgs/LinkCaret.html" with class="ml-4" %} +

+
+
+ {% image page.intro_image original %} +
+ +
+ {% for panel in page.large_panels %} + {% include "ui/components/misc_panels/LinkBlockWithImage.html" with title=panel.value.title image=panel.value.image description=panel.value.description linktext=panel.value.link_text linkurl=panel.value.link_url %} + {% endfor %} +
+
+
+ +
+ {% include "ui/components/sections/BaseSectionWithImage.html" with title=page.resource_learning_title image=page.resource_learning_image imageright=True red_button=True button_text=page.get_connected_button_text button_link=page.get_connected_button_link description=page.resource_learning_description imagenotwide=True %} +
+ +
+
+
+ {% include "ui/components/dogear_boxes/DogearAnyColourLong.html" with title=page.dogear_tech_news_title linktext=page.dogear_tech_news_link_text linkurl=page.dogear_tech_news_link_url textcolour="black" colour="var(--hot-off-white)" arrowcolour="black" %} +
+ +
+
+ {% include "ui/components/dogear_boxes/DogearRed.html" with title=page.red_box_title linktext=page.red_box_link_text linkurl=page.red_box_link_url %} +
+
+ {% include "ui/components/dogear_boxes/DogearBlack.html" with title=page.black_box_title linktext=page.black_box_link_text linkurl=page.black_box_link_url %} +
+
+
+
+{% endblock %} diff --git a/app/tools_and_resources/tests.py b/app/tools_and_resources/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/app/tools_and_resources/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/app/tools_and_resources/views.py b/app/tools_and_resources/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/app/tools_and_resources/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/app/ui/templates/ui/components/BasePageHeader.html b/app/ui/templates/ui/components/BasePageHeader.html index 174943a..cce8bb9 100644 --- a/app/ui/templates/ui/components/BasePageHeader.html +++ b/app/ui/templates/ui/components/BasePageHeader.html @@ -2,9 +2,11 @@ ==> PARAMETERS - title: A string, the title shown in the header - intro: An HTML element (regular usage would be a

with some text in it) +- subtitle: An HTML element - image: A Wagtail image -{% endcomment %} +Only one of either intro or subtitle should be present; you probably would not want both. +{% endcomment %} {% load wagtailimages_tags %} {% image image original as image_p %} @@ -13,21 +15,21 @@

-

+

{{ title }}

{% if intro %} -
+
{{ intro|safe }}
{% endif %}
-
- {% if subtitle %} + {% if subtitle %} +
{{ subtitle|safe }} - {% endif %} -
+
+ {% endif %}
\ No newline at end of file diff --git a/app/ui/templates/ui/components/CTABodyPanelBase.html b/app/ui/templates/ui/components/CTABodyPanelBase.html index 7136626..7d6e8df 100644 --- a/app/ui/templates/ui/components/CTABodyPanelBase.html +++ b/app/ui/templates/ui/components/CTABodyPanelBase.html @@ -1,3 +1,10 @@ +{% comment %} +==> PARAMETERS +- title: string; the title for the panel +- text: html element; the description for the panel +- linktext: string; the text shown for the link +- linkurl: string; the url for the link +{% endcomment %}

{{ title }} diff --git a/app/ui/templates/ui/components/FlexTitleWithLink.html b/app/ui/templates/ui/components/FlexTitleWithLink.html new file mode 100644 index 0000000..ecf2dc6 --- /dev/null +++ b/app/ui/templates/ui/components/FlexTitleWithLink.html @@ -0,0 +1,16 @@ +{% comment %} +==> PARAMETERS +- title: string; the title +- class: string; the classes for the containing div +- titleclass: string; the classes for the title specifically. If no class is provided, the title will be h3 title size +- linktext: string; the text to be shown for the link +- linkurl: string; the url for the link +{% endcomment %} +
+

+ {{title}} +

+

+ {% include "ui/components/BaseLink.html" %} +

+
\ No newline at end of file diff --git a/app/ui/templates/ui/components/FooterBannerWithTextAndLink.html b/app/ui/templates/ui/components/FooterBannerWithTextAndLink.html index b93d3e9..7b9cdf1 100644 --- a/app/ui/templates/ui/components/FooterBannerWithTextAndLink.html +++ b/app/ui/templates/ui/components/FooterBannerWithTextAndLink.html @@ -10,6 +10,11 @@

{{ text }}

+ {% if description %} +
+ {{description|safe}} +
+ {% endif %} {% include "components/branded_elements/button.html" with text=buttontext %} diff --git a/app/ui/templates/ui/components/PageHeaderWithBlur.html b/app/ui/templates/ui/components/PageHeaderWithBlur.html index 3aa41e6..e67f2ed 100644 --- a/app/ui/templates/ui/components/PageHeaderWithBlur.html +++ b/app/ui/templates/ui/components/PageHeaderWithBlur.html @@ -3,6 +3,7 @@ - title: A string, the title shown in the header - subtitle: An HTML element (regular usage would be a

with some text in it) - image: A Wagtail image +- full_length: If falsey/null, the content will not be entirely full length in the header; otherwise, it will be full length {% endcomment %} {% load wagtailimages_tags %} diff --git a/app/ui/templates/ui/components/SectionHeadingWithUnderline.html b/app/ui/templates/ui/components/SectionHeadingWithUnderline.html index a1b5a00..cd31bca 100644 --- a/app/ui/templates/ui/components/SectionHeadingWithUnderline.html +++ b/app/ui/templates/ui/components/SectionHeadingWithUnderline.html @@ -1,3 +1,8 @@ +{% comment %} +==> PARAMETERS +- title: string; the title +{% endcomment %} +

{{ title }}

diff --git a/app/ui/templates/ui/components/ThreeElementCarousel.html b/app/ui/templates/ui/components/ThreeElementCarousel.html index 0e3fed9..00ff572 100644 --- a/app/ui/templates/ui/components/ThreeElementCarousel.html +++ b/app/ui/templates/ui/components/ThreeElementCarousel.html @@ -1,3 +1,13 @@ +{% comment %} +==> PARAMETERS +- carousel: list of blocks; each block should have a .value, which should have: + - .header: string + - .body: string + - .action_button.text: string + - .action_button.link: string + +If you'd like, refer to app.ui.models to see the specifics of what makes up a carousel block. +{% endcomment %}
diff --git a/app/ui/templates/ui/components/TitleWithUnderline.html b/app/ui/templates/ui/components/TitleWithUnderline.html new file mode 100644 index 0000000..af7adc9 --- /dev/null +++ b/app/ui/templates/ui/components/TitleWithUnderline.html @@ -0,0 +1,8 @@ +{% comment %} +==> PARAMETERS +- title: string; the title +{% endcomment %} +

+ {{title}} +

+
diff --git a/app/ui/templates/ui/components/dogear_boxes/DogearAnyColourLong.html b/app/ui/templates/ui/components/dogear_boxes/DogearAnyColourLong.html index 3b0288b..b1f5fdd 100644 --- a/app/ui/templates/ui/components/dogear_boxes/DogearAnyColourLong.html +++ b/app/ui/templates/ui/components/dogear_boxes/DogearAnyColourLong.html @@ -4,15 +4,16 @@ - linkurl: a string; the link's url - linktext: a string; the text that shows for the link - colour: a string; the colour that the box should be (can be hex code or any other CSS compatible colour thing) +- arrowcolour: a string; the colour the arrow should be {% endcomment %} -
+

{{ title }}

{{ linktext }} - + {% include "ui/components/icon_svgs/LinkCaret.html" %} diff --git a/app/ui/templates/ui/components/dogear_boxes/DogearBlack.html b/app/ui/templates/ui/components/dogear_boxes/DogearBlack.html index dd7a5a2..6a3d2fe 100644 --- a/app/ui/templates/ui/components/dogear_boxes/DogearBlack.html +++ b/app/ui/templates/ui/components/dogear_boxes/DogearBlack.html @@ -5,6 +5,6 @@ - linktext: a string; the text that shows for the link {% endcomment %} -
+
{% include "./DogearContent.html" with color="var(--hot-red)" %}
\ No newline at end of file diff --git a/app/ui/templates/ui/components/dogear_boxes/DogearContent.html b/app/ui/templates/ui/components/dogear_boxes/DogearContent.html index 15e7663..ca842a1 100644 --- a/app/ui/templates/ui/components/dogear_boxes/DogearContent.html +++ b/app/ui/templates/ui/components/dogear_boxes/DogearContent.html @@ -1,6 +1,7 @@ {% comment %} ==> PARAMETERS - title: a string; the title of the box +- description: an html element; a description under the title (optional) - linkurl: a string; the link's url - linktext: a string; the text that shows for the link - color: a string; the color that the caret next to the link text should show as @@ -11,6 +12,9 @@

{{ title }}

+{% if description %} +

{{description|safe}}

+{% endif %}

{{ linktext }} diff --git a/app/ui/templates/ui/components/dogear_boxes/DogearRed.html b/app/ui/templates/ui/components/dogear_boxes/DogearRed.html index 3c30e75..384f924 100644 --- a/app/ui/templates/ui/components/dogear_boxes/DogearRed.html +++ b/app/ui/templates/ui/components/dogear_boxes/DogearRed.html @@ -5,6 +5,6 @@ - linktext: a string; the text that shows for the link {% endcomment %} -

+
{% include "./DogearContent.html" %}
\ No newline at end of file diff --git a/app/ui/templates/ui/components/events/EventPreviewBlockEvent.html b/app/ui/templates/ui/components/events/EventPreviewBlockEvent.html index b117e8b..31f2099 100644 --- a/app/ui/templates/ui/components/events/EventPreviewBlockEvent.html +++ b/app/ui/templates/ui/components/events/EventPreviewBlockEvent.html @@ -1,4 +1,18 @@ +{% comment %} +==> PARAMETERS +- event: an IndividualEventPage object; should be passed directly here +{% endcomment %} +{% load wagtailimages_tags %} + +{% image event.image original as image_p %}
+ {% if showimage %} +
+
+
+
+ {% endif %} +
{% if event.start_date_time.date == event.end_date_time.date %}

diff --git a/app/ui/templates/ui/components/icon_svgs/RefreshIcon.html b/app/ui/templates/ui/components/icon_svgs/RefreshIcon.html index 404ea7b..d3b9f21 100644 --- a/app/ui/templates/ui/components/icon_svgs/RefreshIcon.html +++ b/app/ui/templates/ui/components/icon_svgs/RefreshIcon.html @@ -1,3 +1,7 @@ +{% comment %} +==> 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/SearchIcon.html b/app/ui/templates/ui/components/icon_svgs/SearchIcon.html index 1f594b4..27f916a 100644 --- a/app/ui/templates/ui/components/icon_svgs/SearchIcon.html +++ b/app/ui/templates/ui/components/icon_svgs/SearchIcon.html @@ -1,3 +1,7 @@ +{% comment %} +==> PARAMETERS +- class: string; the classes you want for this icon +{% endcomment %} - + diff --git a/app/ui/templates/ui/components/impact_areas/ImpactAreaPreviewBlock.html b/app/ui/templates/ui/components/impact_areas/ImpactAreaPreviewBlock.html new file mode 100644 index 0000000..67edbec --- /dev/null +++ b/app/ui/templates/ui/components/impact_areas/ImpactAreaPreviewBlock.html @@ -0,0 +1,31 @@ +{% comment %} +==> PARAMETERS +- ia: an IndividualImpactAreaPage; should be passed directly here +{% endcomment %} +{% load wagtailimages_tags %} + +{% image ia.header_image original as image_p %} +

\ No newline at end of file diff --git a/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewBlock.html b/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewBlock.html index f20bfad..affd498 100644 --- a/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewBlock.html +++ b/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewBlock.html @@ -2,15 +2,8 @@ ==> PARAMETERS - hub: An IndividualMappingHubPage object; the mapping hub page to be previewed {% endcomment %} - {% load wagtailimages_tags %} -
- {% image hub.main_external_hub_image fill-600x300 %} - -

- {{ hub.title }} -

-
+ {% include "./MappingHubPreviewBlockBase.html" %}
diff --git a/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewBlockBase.html b/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewBlockBase.html new file mode 100644 index 0000000..a6c44fd --- /dev/null +++ b/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewBlockBase.html @@ -0,0 +1,13 @@ +{% comment %} +==> PARAMETERS +- hub: An IndividualMappingHubPage object; the mapping hub page to be previewed +{% endcomment %} +{% load wagtailimages_tags %} + +
+ {% image hub.main_external_hub_image fill-600x300 %} + +

+ {{ hub.title }} +

+
diff --git a/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewExtendedBlock.html b/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewExtendedBlock.html new file mode 100644 index 0000000..851522d --- /dev/null +++ b/app/ui/templates/ui/components/mapping_hub/MappingHubPreviewExtendedBlock.html @@ -0,0 +1,25 @@ +{% comment %} +==> PARAMETERS +- hub: An IndividualMappingHubPage object; the mapping hub page to be previewed +{% endcomment %} +{% load wagtailimages_tags %} + +
+
+ {% image hub.header_image original class="col-start-1 row-start-1 aspect-[2/1] object-cover" %} +
+
+
+
+ {% image hub.main_icon original class="w-14 h-auto" %} +

+ {{hub.title}} {{hub_text}} +

+
+
+ {{hub.intro|safe}} +
+

+ {% 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/members/MemberPreviewBlock.html b/app/ui/templates/ui/components/members/MemberPreviewBlock.html new file mode 100644 index 0000000..a1a5bbd --- /dev/null +++ b/app/ui/templates/ui/components/members/MemberPreviewBlock.html @@ -0,0 +1,24 @@ +{% load wagtailimages_tags %} + + \ No newline at end of file diff --git a/app/ui/templates/ui/components/misc_panels/LinkBlockWithImage.html b/app/ui/templates/ui/components/misc_panels/LinkBlockWithImage.html new file mode 100644 index 0000000..3eadf13 --- /dev/null +++ b/app/ui/templates/ui/components/misc_panels/LinkBlockWithImage.html @@ -0,0 +1,19 @@ +{% comment %} +==> PARAMETERS +- title: string; the title +- description: html element; the description of the block +- linktext: string; the text to show for the link +- linkurl: string; the desired url +{% endcomment %} +{% load wagtailimages_tags %} + +
+ {% image image original class="aspect-[2/1] object-cover" %} +

{{title}}

+
+ {{description}} +
+

+ {% include "ui/components/BaseLink.html" %} +

+
\ No newline at end of file diff --git a/app/ui/templates/ui/components/misc_panels/PagePreviewBasic.html b/app/ui/templates/ui/components/misc_panels/PagePreviewBasic.html new file mode 100644 index 0000000..3c6429a --- /dev/null +++ b/app/ui/templates/ui/components/misc_panels/PagePreviewBasic.html @@ -0,0 +1,19 @@ +{% comment %} +==> PARAMETERS +- page: Page object; its link and title is used here +- previmg: image object; the image for the preview +{% endcomment %} +{% load wagtailimages_tags %} + +{% image image original as previmg %} + +
+
+
+
+

+ {{page.title}} +

+
+
+
\ No newline at end of file diff --git a/app/ui/templates/ui/components/misc_panels/PagePreviewWithTabletDescription.html b/app/ui/templates/ui/components/misc_panels/PagePreviewWithTabletDescription.html new file mode 100644 index 0000000..eb1db9d --- /dev/null +++ b/app/ui/templates/ui/components/misc_panels/PagePreviewWithTabletDescription.html @@ -0,0 +1,31 @@ +{% comment %} +==> PARAMETERS +- page: Page object; its link and title is used here +- previmg: image object; the image for the preview +- tablet_description: html element; the description of the block, which only shows on tablet sizes and smaller +- read_more_text: string; the text to show for "read more" +{% endcomment %} +{% load wagtailimages_tags %} + +{% image image original as previmg %} + +
+
+
+ +
+
+

{{page.title}}

+
+ {{tablet_description}} +
+

+ {{read_more_text}} + {% include "ui/components/icon_svgs/LinkCaret.html" with class="ml-2" %} +

+
+
\ No newline at end of file diff --git a/app/ui/templates/ui/components/navigation/FooterNavigation.html b/app/ui/templates/ui/components/navigation/FooterNavigation.html index 38f5427..2aa3619 100644 --- a/app/ui/templates/ui/components/navigation/FooterNavigation.html +++ b/app/ui/templates/ui/components/navigation/FooterNavigation.html @@ -1,3 +1,6 @@ +{% comment %} +No parameters; it grabs directly from the home page (for the correct locale). +{% endcomment %} {% load homepage_tags %} {% get_home_page as home_page %} {% get_navigation as navigation %} diff --git a/app/ui/templates/ui/components/navigation/HeaderNavbar.html b/app/ui/templates/ui/components/navigation/HeaderNavbar.html index 3bfe9fc..2a49392 100644 --- a/app/ui/templates/ui/components/navigation/HeaderNavbar.html +++ b/app/ui/templates/ui/components/navigation/HeaderNavbar.html @@ -1,3 +1,6 @@ +{% comment %} +No parameters; it grabs directly from the home page (for the correct locale). +{% endcomment %} {% load homepage_tags %} {% get_navigation as navigation %} {% get_home_page as home_page %} @@ -50,6 +53,7 @@ {% comment %} MOBILE EXPANDED LIST {% endcomment %}
    +
  • {% include "ui/components/navigation/SearchForm.html" %}
  • {% for item in navigation %}
  • {% include "ui/components/navigation/HeaderNavbarItem.html" with item=item.value %} diff --git a/app/ui/templates/ui/components/navigation/HeaderNavbarButton.html b/app/ui/templates/ui/components/navigation/HeaderNavbarButton.html index 22f0dd0..39a73a2 100644 --- a/app/ui/templates/ui/components/navigation/HeaderNavbarButton.html +++ b/app/ui/templates/ui/components/navigation/HeaderNavbarButton.html @@ -1,3 +1,7 @@ +{% comment %} +==> PARAMETERS +- item: a navigation item; has a title and a link_page OR link_url +{% endcomment %}

    diff --git a/app/ui/templates/ui/components/navigation/HeaderNavbarItem.html b/app/ui/templates/ui/components/navigation/HeaderNavbarItem.html index 764ac4b..3a9d72d 100644 --- a/app/ui/templates/ui/components/navigation/HeaderNavbarItem.html +++ b/app/ui/templates/ui/components/navigation/HeaderNavbarItem.html @@ -1,3 +1,8 @@ +{% comment %} +==> PARAMETERS +- item: a navigation item; has a title and a link_page OR link_url, as well as potentially children + - these children will have the same parameters, and those children's children will have the same except they cannot have children +{% endcomment %}

    diff --git a/app/ui/templates/ui/components/navigation/SearchForm.html b/app/ui/templates/ui/components/navigation/SearchForm.html new file mode 100644 index 0000000..f10fa9a --- /dev/null +++ b/app/ui/templates/ui/components/navigation/SearchForm.html @@ -0,0 +1,21 @@ +{% comment %} +==> PARAMETERS +- has_ref: optional; if Truthy, this will have an x-ref + - means that this form can be focused via alpinejs; if multiple have this ref it obviously won't work for all of them +{% endcomment %} +

    + + + \ No newline at end of file diff --git a/app/ui/templates/ui/components/navigation/SearchModal.html b/app/ui/templates/ui/components/navigation/SearchModal.html new file mode 100644 index 0000000..17d224f --- /dev/null +++ b/app/ui/templates/ui/components/navigation/SearchModal.html @@ -0,0 +1,19 @@ +{% comment %} +No parameters; this component is only used for the search popup on desktop sizes. +{% endcomment %} + diff --git a/app/ui/templates/ui/components/news/NewsPreviewBlockNews.html b/app/ui/templates/ui/components/news/NewsPreviewBlockNews.html index 075345d..f3aa44a 100644 --- a/app/ui/templates/ui/components/news/NewsPreviewBlockNews.html +++ b/app/ui/templates/ui/components/news/NewsPreviewBlockNews.html @@ -4,7 +4,7 @@ - readmoretext: a string; the text that should show for the "read more" button {% endcomment %} -
    +

    {{ news.date }} diff --git a/app/ui/templates/ui/components/news/NewsPreviewBlockProjects.html b/app/ui/templates/ui/components/news/NewsPreviewBlockProjects.html index 263fa54..8a97511 100644 --- a/app/ui/templates/ui/components/news/NewsPreviewBlockProjects.html +++ b/app/ui/templates/ui/components/news/NewsPreviewBlockProjects.html @@ -1,12 +1,12 @@ {% comment %} ==> PARAMETERS - 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 wagtailimages_tags %} {% image news.image original as image_p %} -

    +
    {% if showimage %}
    diff --git a/app/ui/templates/ui/components/news/NewsPreviewCarousel.html b/app/ui/templates/ui/components/news/NewsPreviewCarousel.html index 70da95e..3bec76f 100644 --- a/app/ui/templates/ui/components/news/NewsPreviewCarousel.html +++ b/app/ui/templates/ui/components/news/NewsPreviewCarousel.html @@ -1,3 +1,8 @@ +{% comment %} +==> PARAMETERS +- news: list of IndividualNewsPages +- title: string; an optional title for the section +{% endcomment %} {% load wagtailimages_tags %}
    @@ -27,7 +32,7 @@

    -
    +
    {% for article in news %}
    TODO: -- make the system of assigning order smarter because it's kind of. unwieldy. as you can see {% endcomment %} {% load wagtailimages_tags %} diff --git a/app/ui/templates/ui/components/programs/ProgramCarouselBlock.html b/app/ui/templates/ui/components/programs/ProgramCarouselBlock.html index a9fca4d..1e29732 100644 --- a/app/ui/templates/ui/components/programs/ProgramCarouselBlock.html +++ b/app/ui/templates/ui/components/programs/ProgramCarouselBlock.html @@ -1,3 +1,7 @@ +{% comment %} +==> PARAMETERS +- programs: a list of IndividualProgramPages +{% endcomment %} {% load wagtailimages_tags %}
    diff --git a/app/ui/templates/ui/components/projects/ProjectPreviewBlockMapHub.html b/app/ui/templates/ui/components/projects/ProjectPreviewBlockMapHub.html index ab76a6e..a7c09bf 100644 --- a/app/ui/templates/ui/components/projects/ProjectPreviewBlockMapHub.html +++ b/app/ui/templates/ui/components/projects/ProjectPreviewBlockMapHub.html @@ -1,13 +1,13 @@ {% comment %} ==> PARAMETERS - project: An IndividualProjectPage object; the project page to be previewed -- showimage: a boolean; whether or not the image should be shown in the preview +- showimage: optional; if truthy, the project's image will be shown in the preview {% endcomment %} {% load wagtailimages_tags %} {% image project.header_image original as image_p %} -
    +
    {% if showimage %} @@ -30,8 +30,8 @@

    - - {{ project.owner_region_hub.title }} - + {% for hub in project.region_hub_list %} + {{ hub.value.title }}{% if not forloop.last %},{% endif %} + {% endfor %}

    \ No newline at end of file diff --git a/app/ui/templates/ui/components/projects/ProjectPreviewBlockNews.html b/app/ui/templates/ui/components/projects/ProjectPreviewBlockNews.html index 222ffed..b8b33f2 100644 --- a/app/ui/templates/ui/components/projects/ProjectPreviewBlockNews.html +++ b/app/ui/templates/ui/components/projects/ProjectPreviewBlockNews.html @@ -1,13 +1,13 @@ {% comment %} ==> PARAMETERS - project: An IndividualProjectPage object; the project page to be previewed -- showimage: a boolean; whether or not the image should be shown in the preview +- showimage: optional; if truthy, the project's image will be shown in the preview {% endcomment %} {% load wagtailimages_tags %} {% image project.header_image original as image_p %} -
    +
    {% if showimage %} diff --git a/app/ui/templates/ui/components/projects/ProjectPreviewCarousel.html b/app/ui/templates/ui/components/projects/ProjectPreviewCarousel.html index 05ac3cd..2578fcc 100644 --- a/app/ui/templates/ui/components/projects/ProjectPreviewCarousel.html +++ b/app/ui/templates/ui/components/projects/ProjectPreviewCarousel.html @@ -1,3 +1,8 @@ +{% comment %} +==> PARAMETERS +- projects: list of IndividualProjectPages +- title: string; an optional title for the section +{% endcomment %} {% load wagtailimages_tags %}
    @@ -27,7 +32,7 @@

    -
    +
    {% for project in projects %} \ No newline at end of file diff --git a/app/ui/templates/ui/components/sections/GreyBackgroundWithImage.html b/app/ui/templates/ui/components/sections/GreyBackgroundWithImage.html new file mode 100644 index 0000000..bd6f16d --- /dev/null +++ b/app/ui/templates/ui/components/sections/GreyBackgroundWithImage.html @@ -0,0 +1,21 @@ +{% comment %} +==> PARAMETERS +- image: image object; the image for the section +- title: html element; the title for the section +- description: html element; the description for the section +- button2_text: string; the left button's text +- button2_link: string; the left button's link +- button_text: string; the right button's text +- button_link: string; the right button's link + +- red_button: if truthy, the right button will be red; otherwise it will be outlined +- bigdescription: if truthy, the description will have larger text +- imagebottom: if truthy, the image will always be on the bottom in tablet/mobile sizes +- 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 wagtailimages_tags %} + +
    + {% include "./BaseSectionWithImage.html" %} +
    \ No newline at end of file diff --git a/app/ui/templates/ui/components/sections/LinkListSection.html b/app/ui/templates/ui/components/sections/LinkListSection.html new file mode 100644 index 0000000..c2326d9 --- /dev/null +++ b/app/ui/templates/ui/components/sections/LinkListSection.html @@ -0,0 +1,20 @@ +{% comment %} +==> PARAMETERS +- title: string; the title +- 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 %} +

    {{title}}

    +
    +
    +
    + {{description|safe}} +
    +
    + {% for link in links %} +

    + {% include "ui/components/BaseLink.html" with linktext=link.value.text linkurl=link.value.link %} +

    + {% endfor %} +
    +
    diff --git a/app/ui/templates/ui/components/sections/NavyBackgroundWithImage.html b/app/ui/templates/ui/components/sections/NavyBackgroundWithImage.html new file mode 100644 index 0000000..86801e5 --- /dev/null +++ b/app/ui/templates/ui/components/sections/NavyBackgroundWithImage.html @@ -0,0 +1,21 @@ +{% comment %} +==> PARAMETERS +- image: image object; the image for the section +- title: html element; the title for the section +- description: html element; the description for the section +- button2_text: string; the left button's text +- button2_link: string; the left button's link +- button_text: string; the right button's text +- button_link: string; the right button's link + +- red_button: if truthy, the right button will be red; otherwise it will be outlined +- bigdescription: if truthy, the description will have larger text +- imagebottom: if truthy, the image will always be on the bottom in tablet/mobile sizes +- 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 wagtailimages_tags %} + +
    + {% include "./BaseSectionWithImage.html" %} +
    \ No newline at end of file diff --git a/app/ui/templates/ui/components/sharers/ShareSection.html b/app/ui/templates/ui/components/sharers/ShareSection.html index a7782da..be28251 100644 --- a/app/ui/templates/ui/components/sharers/ShareSection.html +++ b/app/ui/templates/ui/components/sharers/ShareSection.html @@ -1,3 +1,8 @@ +{% comment %} +==> PARAMETERS +- class: string; the classes for the containing div +- sharetext: string; the text to be shown next to the share icons +{% endcomment %}

    diff --git a/app/ui/templates/ui/components/utilities/PaginatorNavigation.html b/app/ui/templates/ui/components/utilities/PaginatorNavigation.html new file mode 100644 index 0000000..e2ed781 --- /dev/null +++ b/app/ui/templates/ui/components/utilities/PaginatorNavigation.html @@ -0,0 +1,47 @@ +{% comment %} +PARAMETERS: +=> paginator: a paginator object +=> current_page: an integer, the current page +{% endcomment %} +

    +
    + +

    + {% include "ui/components/icon_svgs/LinkCaret.html" with class="rotate-180" %} +

    +
    +
    + {% with ''|center:paginator.num_pages as range %} + {% for _ in range %} + {% if forloop.counter == 1 or forloop.counter == paginator.num_pages or forloop.counter == current_page or forloop.counter|add:1 == current_page or forloop.counter|add:'-1' == current_page %} + +

    + {{forloop.counter}} +

    +
    + {% endif %} + {% if forloop.counter|add:2 == current_page or forloop.counter|add:'-2' == current_page and not forloop.last %} + {% comment %} + for reasons that i can't begin to comprehend, the if statement + below CANNOT be part of the if statement above. it just does + not work + {% endcomment %} + {% if not forloop.first %} +

    ...

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

    + {% include "ui/components/icon_svgs/LinkCaret.html" %} +

    +
    +
    +
    diff --git a/app/who_we_are/__init__.py b/app/who_we_are/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/who_we_are/admin.py b/app/who_we_are/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/app/who_we_are/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/app/who_we_are/apps.py b/app/who_we_are/apps.py new file mode 100644 index 0000000..3886c18 --- /dev/null +++ b/app/who_we_are/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class WhoWeAreConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'app.who_we_are' diff --git a/app/who_we_are/migrations/0001_initial.py b/app/who_we_are/migrations/0001_initial.py new file mode 100644 index 0000000..24fa268 --- /dev/null +++ b/app/who_we_are/migrations/0001_initial.py @@ -0,0 +1,61 @@ +# Generated by Django 4.2.7 on 2024-06-28 19:58 + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks + + +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='WhoWeArePage', + 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')), + ('intro', wagtail.fields.RichTextField(blank=True)), + ('learn_more_button_text', models.CharField(default='Learn More About Our Living Strategy')), + ('learn_more_button_url', models.URLField(blank=True)), + ('intro_info_blocks', wagtail.fields.StreamField([('info_block', wagtail.blocks.StructBlock([('image', wagtail.images.blocks.ImageChooserBlock()), ('title', wagtail.blocks.CharBlock(blank=True)), ('description', wagtail.blocks.CharBlock(blank=True))]))], null=True, use_json_field=True)), + ('our_approach_title', models.CharField(default='Our Approach')), + ('our_approach_description', models.CharField(blank=True)), + ('our_approach_button_url', models.URLField(blank=True)), + ('our_approach_button_text', models.CharField(default='Our Approach')), + ('our_people_title', models.CharField(default='Our People')), + ('our_people_description', wagtail.fields.RichTextField(blank=True)), + ('our_people_links', wagtail.fields.StreamField([('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.CharBlock()), ('link', wagtail.blocks.URLBlock(blank=True))]))], null=True, use_json_field=True)), + ('other_page_preview_blocks', wagtail.fields.StreamField([('other_page_preview', wagtail.blocks.StructBlock([('image', wagtail.images.blocks.ImageChooserBlock()), ('page', wagtail.blocks.PageChooserBlock())]))], null=True, use_json_field=True)), + ('partners_title', models.CharField(default='Meet Our Partners')), + ('partners_view_all_text', models.CharField(default='View All Partners')), + ('partners_view_all_url', models.URLField(blank=True)), + ('work_hot_title', models.CharField(default='Work for HOT')), + ('work_hot_description', wagtail.fields.RichTextField(blank=True)), + ('work_hot_button_text', models.CharField(default='View all Job Opportunities')), + ('work_hot_button_link', models.URLField(blank=True)), + ('our_policies_title', models.CharField(default='Our Policies')), + ('our_policies_description', wagtail.fields.RichTextField(blank=True)), + ('our_policies_links', wagtail.fields.StreamField([('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.CharBlock()), ('link', wagtail.blocks.URLBlock(blank=True))]))], null=True, use_json_field=True)), + ('red_box_title', models.CharField(default='Annual Reports')), + ('red_box_link_text', models.CharField(default='Access our annual report archive.')), + ('red_box_link_url', models.URLField(blank=True, null=True)), + ('black_box_title', models.CharField(default='Our Financial Reports')), + ('black_box_link_text', models.CharField(default='Access older financial reports and organization bylaws in our archive.')), + ('black_box_link_url', models.URLField(blank=True, null=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')), + ('our_approach_image', models.ForeignKey(blank=True, help_text='Our approach image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image')), + ('work_hot_image', models.ForeignKey(blank=True, help_text='Work for HOT section 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/who_we_are/migrations/0002_whowearepage_partners_and_more.py b/app/who_we_are/migrations/0002_whowearepage_partners_and_more.py new file mode 100644 index 0000000..c43c3c2 --- /dev/null +++ b/app/who_we_are/migrations/0002_whowearepage_partners_and_more.py @@ -0,0 +1,43 @@ +# Generated by Django 4.2.7 on 2024-06-28 23:12 + +from django.db import migrations +import modelcluster.fields +import wagtail.blocks +import wagtail.fields +import wagtail.images.blocks + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0002_alter_partner_partner_logo_alter_partner_partner_url'), + ('who_we_are', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='whowearepage', + name='partners', + field=modelcluster.fields.ParentalManyToManyField(blank=True, to='core.partner'), + ), + migrations.AlterField( + model_name='whowearepage', + name='intro_info_blocks', + field=wagtail.fields.StreamField([('info_block', wagtail.blocks.StructBlock([('image', wagtail.images.blocks.ImageChooserBlock()), ('title', wagtail.blocks.CharBlock(blank=True)), ('description', wagtail.blocks.RichTextBlock(blank=True, required=False))]))], blank=True, null=True, use_json_field=True), + ), + migrations.AlterField( + model_name='whowearepage', + name='other_page_preview_blocks', + field=wagtail.fields.StreamField([('other_page_preview', wagtail.blocks.StructBlock([('image', wagtail.images.blocks.ImageChooserBlock()), ('page', wagtail.blocks.PageChooserBlock())]))], blank=True, null=True, use_json_field=True), + ), + migrations.AlterField( + model_name='whowearepage', + name='our_people_links', + field=wagtail.fields.StreamField([('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.CharBlock()), ('link', wagtail.blocks.URLBlock(blank=True, required=False))]))], blank=True, null=True, use_json_field=True), + ), + migrations.AlterField( + model_name='whowearepage', + name='our_policies_links', + field=wagtail.fields.StreamField([('link_block', wagtail.blocks.StructBlock([('text', wagtail.blocks.CharBlock()), ('link', wagtail.blocks.URLBlock(blank=True, required=False))]))], blank=True, null=True, use_json_field=True), + ), + ] diff --git a/app/who_we_are/migrations/0003_whowearepage_black_box_description_and_more.py b/app/who_we_are/migrations/0003_whowearepage_black_box_description_and_more.py new file mode 100644 index 0000000..5e3cd78 --- /dev/null +++ b/app/who_we_are/migrations/0003_whowearepage_black_box_description_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 4.2.7 on 2024-07-02 17:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('who_we_are', '0002_whowearepage_partners_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='whowearepage', + name='black_box_description', + field=models.CharField(default='Access older financial reports and organization bylaws in our archive.'), + ), + migrations.AddField( + model_name='whowearepage', + name='red_box_description', + field=models.CharField(default='Access our annual report archive.'), + ), + migrations.AlterField( + model_name='whowearepage', + name='black_box_link_text', + field=models.CharField(default='Check all Financial Reports'), + ), + migrations.AlterField( + model_name='whowearepage', + name='red_box_link_text', + field=models.CharField(default='Check all Annual Reports'), + ), + ] diff --git a/app/who_we_are/migrations/0004_alter_whowearepage_black_box_description_and_more.py b/app/who_we_are/migrations/0004_alter_whowearepage_black_box_description_and_more.py new file mode 100644 index 0000000..d60c861 --- /dev/null +++ b/app/who_we_are/migrations/0004_alter_whowearepage_black_box_description_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.7 on 2024-07-02 17:17 + +from django.db import migrations +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('who_we_are', '0003_whowearepage_black_box_description_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='whowearepage', + name='black_box_description', + field=wagtail.fields.RichTextField(default='Access older financial reports and organization bylaws in our archive.'), + ), + migrations.AlterField( + model_name='whowearepage', + name='red_box_description', + field=wagtail.fields.RichTextField(default='Access our annual report archive.'), + ), + ] diff --git a/app/who_we_are/migrations/__init__.py b/app/who_we_are/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/who_we_are/models.py b/app/who_we_are/models.py new file mode 100644 index 0000000..f0f2029 --- /dev/null +++ b/app/who_we_are/models.py @@ -0,0 +1,143 @@ +from django import forms +from django.db import models + +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 wagtail.images.blocks import ImageChooserBlock + + +class IntroInfoBlock(StructBlock): + image = ImageChooserBlock() + title = CharBlock(blank=True) + description = RichTextBlock(blank=True, required=False) + + +class TextAndLinkBlock(StructBlock): + text = CharBlock() + link = URLBlock(blank=True, required=False) + + +class OtherPagePreviewBlock(StructBlock): + image = ImageChooserBlock() + page = PageChooserBlock() + + +class WhoWeArePage(Page): + max_count = 1 + + header_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Header image" + ) + intro = RichTextField(blank=True) + learn_more_button_text = models.CharField(default="Learn More About Our Living Strategy") + learn_more_button_url = models.URLField(blank=True) + intro_info_blocks = StreamField([('info_block', IntroInfoBlock())], use_json_field=True, null=True, blank=True) + + our_approach_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Our approach image" + ) + our_approach_title = models.CharField(default="Our Approach") + our_approach_description = models.CharField(blank=True) + our_approach_button_url = models.URLField(blank=True) + our_approach_button_text = models.CharField(default="Our Approach") + + our_people_title = models.CharField(default="Our People") + our_people_description = RichTextField(blank=True) + our_people_links = StreamField([('link_block', TextAndLinkBlock())], use_json_field=True, null=True, blank=True) + + other_page_preview_blocks = StreamField([('other_page_preview', OtherPagePreviewBlock())], use_json_field=True, null=True, blank=True) + + partners_title = models.CharField(default="Meet Our Partners") + partners_view_all_text = models.CharField(default="View All Partners") + partners_view_all_url = models.URLField(blank=True) + partners = ParentalManyToManyField('core.Partner', blank=True) + + work_hot_image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Work for HOT section image", + ) + work_hot_title = models.CharField(default="Work for HOT") + work_hot_description = RichTextField(blank=True) + work_hot_button_text = models.CharField(default="View all Job Opportunities") + work_hot_button_link = models.URLField(blank=True) + + our_policies_title = models.CharField(default="Our Policies") + our_policies_description = RichTextField(blank=True) + our_policies_links = StreamField([('link_block', TextAndLinkBlock())], use_json_field=True, null=True, blank=True) + + red_box_title = models.CharField(default="Annual Reports") + red_box_description = RichTextField(default="Access our annual report archive.") + red_box_link_text = models.CharField(default="Check all Annual Reports") + red_box_link_url = models.URLField(null=True, blank=True) + black_box_title = models.CharField(default="Our Financial Reports") + black_box_description = RichTextField(default="Access older financial reports and organization bylaws in our archive.") + black_box_link_text = models.CharField(default="Check all Financial Reports") + black_box_link_url = models.URLField(null=True, blank=True) + + content_panels = Page.content_panels + [ + MultiFieldPanel([ + FieldPanel('header_image'), + FieldPanel('intro'), + FieldPanel('learn_more_button_text'), + FieldPanel('learn_more_button_url'), + FieldPanel('intro_info_blocks'), + ], heading="Introduction"), + MultiFieldPanel([ + FieldPanel('our_approach_image'), + FieldPanel('our_approach_title'), + FieldPanel('our_approach_description'), + FieldPanel('our_approach_button_url'), + FieldPanel('our_approach_button_text'), + ], heading="Our Approach"), + MultiFieldPanel([ + FieldPanel('our_people_title'), + FieldPanel('our_people_description'), + FieldPanel('our_people_links'), + ], heading="Our People"), + FieldPanel('other_page_preview_blocks'), + MultiFieldPanel([ + FieldPanel('partners_title'), + FieldPanel('partners_view_all_text'), + FieldPanel('partners_view_all_url'), + FieldPanel('partners', widget=forms.CheckboxSelectMultiple), + ], heading="Partners"), + MultiFieldPanel([ + FieldPanel('work_hot_image'), + FieldPanel('work_hot_title'), + FieldPanel('work_hot_description'), + FieldPanel('work_hot_button_text'), + FieldPanel('work_hot_button_link'), + ], heading="Work for HOT"), + MultiFieldPanel([ + FieldPanel('our_policies_title'), + FieldPanel('our_policies_description'), + FieldPanel('our_policies_links'), + ], heading="Our Policies"), + MultiFieldPanel([ + FieldPanel('red_box_title'), + FieldPanel('red_box_description'), + FieldPanel('red_box_link_text'), + FieldPanel('red_box_link_url'), + FieldPanel('black_box_title'), + FieldPanel('black_box_description'), + FieldPanel('black_box_link_text'), + FieldPanel('black_box_link_url'), + ], heading="Dogear Boxes"), + ] diff --git a/app/who_we_are/templates/who_we_are/who_we_are_page.html b/app/who_we_are/templates/who_we_are/who_we_are_page.html new file mode 100644 index 0000000..8acaf8d --- /dev/null +++ b/app/who_we_are/templates/who_we_are/who_we_are_page.html @@ -0,0 +1,97 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-individualprojectpage{% endblock %} +{% block extra_css %} + {% compress css %} + {% endcompress css %} +{% endblock extra_css %} + +{% block content %} + {% comment %} INTRO {% endcomment %} + {% include "ui/components/BasePageHeader.html" with title=page.title image=page.header_image %} +
    +
    +
    + + +
    + {% for block in page.intro_info_blocks %} +
    + {% image block.value.image original class="h-10 w-auto" %} +
    +

    {{block.value.title}}

    + {{block.value.description|safe}} +
    +
    + {% endfor %} +
    +
    +
    +
    + + {% comment %} OUR APPROACH {% endcomment %} + {% include "ui/components/sections/NavyBackgroundWithImage.html" with title=page.our_approach_title description=page.our_approach_description button_text=page.our_approach_button_text button_link=page.our_approach_button_url image=page.our_approach_image title_underline=True %} + + {% comment %} OUR PEOPLE {% endcomment %} +
    +
    + {% include "ui/components/sections/LinkListSection.html" with title=page.our_people_title description=page.our_people_description links=page.our_people_links %} +
    +
    + +
    +
    + {% comment %} PAGE PREVIEWS {% endcomment %} +
    + {% for prev in page.other_page_preview_blocks %} + {% include "ui/components/misc_panels/PagePreviewBasic.html" with page=prev.value.page image=prev.value.image %} + {% endfor %} +
    + + {% comment %} PARTNERS {% endcomment %} +
    +
    +

    + {{ page.partners_title }} +

    +
    +
    + +
    + {% include "ui/components/BaseLink.html" with linkurl=page.partners_view_all_url linktext=page.partners_view_all_text %} +
    +
    + {% include "ui/components/partners/PartnerViewBlock.html" with partners=page.partners.all %} +
    +
    + + {% comment %} OPPORTUNITIES {% endcomment %} + {% include "home/components/CheckOutOpportunitiesSection.html" %} + {% comment %} WORK FOR HOT {% endcomment %} + {% include "ui/components/sections/GreyBackgroundWithImage.html" with image=page.work_hot_image title=page.work_hot_title description=page.work_hot_description button_text=page.work_hot_button_text button_link=page.work_hot_button_url red_button=True %} + +
    +
    + {% include "ui/components/sections/LinkListSection.html" with title=page.our_policies_title description=page.our_policies_description links=page.our_policies_links %} +
    +
    + +
    +
    +
    + {% include "ui/components/dogear_boxes/DogearRed.html" with title=page.red_box_title description=page.red_box_description linktext=page.red_box_link_text linkurl=page.red_box_link_url %} + {% include "ui/components/dogear_boxes/DogearBlack.html" with title=page.black_box_title description=page.black_box_description linktext=page.black_box_link_text linkurl=page.black_box_link_url %} +
    +
    +
    +{% endblock %} diff --git a/app/who_we_are/tests.py b/app/who_we_are/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/app/who_we_are/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/app/who_we_are/views.py b/app/who_we_are/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/app/who_we_are/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/home/models.py b/home/models.py index 21a59c0..8b2da06 100644 --- a/home/models.py +++ b/home/models.py @@ -58,6 +58,8 @@ def get_context(self, request, *args, **kwargs): context['mapping_hubs'] = mapping_hubs return context + max_count = 1 + templates = "home/home_page.html" # Navigation @@ -210,16 +212,13 @@ def get_context(self, request, *args, **kwargs): FieldPanel('footer_bottom_copyright'), FieldPanel('footer_bottom_links'), ], heading="Navigation"), - MultiFieldPanel( - [ - FieldPanel("image"), - FieldPanel("hero_text"), - FieldPanel("hero_cta"), - FieldPanel("hero_cta_link"), - FieldPanel("carousel"), - ], - heading="Banner", - ), + MultiFieldPanel([ + FieldPanel("image"), + FieldPanel("hero_text"), + FieldPanel("hero_cta"), + FieldPanel("hero_cta_link"), + FieldPanel("carousel"), + ], heading="Banner"), MultiFieldPanel([ FieldPanel('our_work_background'), FieldPanel('our_work_title'), diff --git a/home/templates/home/components/CheckOutOpportunitiesSection.html b/home/templates/home/components/CheckOutOpportunitiesSection.html new file mode 100644 index 0000000..5e10d54 --- /dev/null +++ b/home/templates/home/components/CheckOutOpportunitiesSection.html @@ -0,0 +1,27 @@ +{% load homepage_tags %} +{% get_home_page as home_page %} +{% load wagtailimages_tags %} + +{% comment %} OPPORTUNITIES {% endcomment %} +
    +
    + {% image home_page.opportunities_image original as op_image %} +
    + +
    +
    diff --git a/home/templates/home/home_page.html b/home/templates/home/home_page.html index 1c9003d..60ed227 100644 --- a/home/templates/home/home_page.html +++ b/home/templates/home/home_page.html @@ -136,28 +136,7 @@

    {% comment %} OPPORTUNITIES {% endcomment %} -
    - -
    + {% include "home/components/CheckOutOpportunitiesSection.html" %}
    {% comment %} NEWS {% endcomment %} @@ -170,7 +149,7 @@

    -
    +
    {% for news in page.displayed_news %}
    {% include "ui/components/news/NewsPreviewBlockProjects.html" with news=news.value showimage=True %} diff --git a/hot_osm/settings/base.py b/hot_osm/settings/base.py index 2a45387..725d67c 100644 --- a/hot_osm/settings/base.py +++ b/hot_osm/settings/base.py @@ -44,6 +44,10 @@ "app.mapping_hubs", "app.members", "app.events", + "app.who_we_are", + "app.get_involved", + "app.tools_and_resources", + "app.search_page", "search", "users", "utils", diff --git a/hot_osm/static/css/hot_osm.css b/hot_osm/static/css/hot_osm.css index dfc811e..430b76b 100644 --- a/hot_osm/static/css/hot_osm.css +++ b/hot_osm/static/css/hot_osm.css @@ -199,4 +199,8 @@ .bold-override b { font-weight: inherit; +} + +.black-image-redifier { + filter: invert(23%) sepia(93%) saturate(1690%) hue-rotate(340deg) brightness(110%) contrast(81%); } \ No newline at end of file diff --git a/hot_osm/templates/base.html b/hot_osm/templates/base.html index 96a4c26..790dad1 100644 --- a/hot_osm/templates/base.html +++ b/hot_osm/templates/base.html @@ -49,6 +49,7 @@ {% include "components/nav/secondary_desktop_nav.html" %}
    {% comment %} {% include "components/header/header.html" %} {% endcomment %} + {% include "ui/components/navigation/SearchModal.html" %} {% include "ui/components/navigation/HeaderNavbar.html" %} {% block content %} {% endblock content %} diff --git a/hot_osm/templates/components/nav/secondary_desktop_nav.html b/hot_osm/templates/components/nav/secondary_desktop_nav.html index f61c929..916387b 100644 --- a/hot_osm/templates/components/nav/secondary_desktop_nav.html +++ b/hot_osm/templates/components/nav/secondary_desktop_nav.html @@ -1,6 +1,6 @@ {% load i18n %} -