diff --git a/app/core/models.py b/app/core/models.py index cc04e8e..9e66f7b 100644 --- a/app/core/models.py +++ b/app/core/models.py @@ -1,6 +1,7 @@ from django.db import models from wagtail.models import Page -from wagtail.fields import RichTextField +from wagtail.fields import StreamField +from wagtail.blocks import CharBlock, StreamBlock, StructBlock, URLBlock, RichTextBlock, PageChooserBlock from wagtail.snippets.models import register_snippet from wagtail.admin.panels import FieldPanel, MultiFieldPanel, InlinePanel @@ -29,3 +30,11 @@ def __str__(self): class Meta: verbose_name_plural = "Partners" + + +class LinkOrPageBlock(StreamBlock): + page = PageChooserBlock() + url = URLBlock() + + class Meta: + max_num = 1 diff --git a/app/misc/__init__.py b/app/misc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/misc/admin.py b/app/misc/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/app/misc/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/app/misc/apps.py b/app/misc/apps.py new file mode 100644 index 0000000..39bf44d --- /dev/null +++ b/app/misc/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MiscConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'app.misc' diff --git a/app/misc/migrations/0001_initial.py b/app/misc/migrations/0001_initial.py new file mode 100644 index 0000000..d0f060e --- /dev/null +++ b/app/misc/migrations/0001_initial.py @@ -0,0 +1,32 @@ +# Generated by Django 4.2.7 on 2024-07-17 18:08 + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('wagtailcore', '0089_log_entry_data_json_null_to_object'), + ('wagtailimages', '0025_alter_image_file_alter_rendition_file'), + ] + + operations = [ + migrations.CreateModel( + name='WorkingGroupsPage', + 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='This is shown in the header.')), + ('working_groups', wagtail.fields.StreamField([('working_group', wagtail.blocks.StructBlock([('title', wagtail.blocks.CharBlock()), ('description', wagtail.blocks.RichTextBlock()), ('links', wagtail.blocks.StreamBlock([('link', wagtail.blocks.StructBlock([('text', wagtail.blocks.CharBlock()), ('link', wagtail.blocks.URLBlock(required=False))]))]))]))], blank=True, null=True, use_json_field=True)), + ('header_image', models.ForeignKey(blank=True, help_text='Header image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image')), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + ] diff --git a/app/misc/migrations/0002_joinourconversationpage.py b/app/misc/migrations/0002_joinourconversationpage.py new file mode 100644 index 0000000..25dd2f0 --- /dev/null +++ b/app/misc/migrations/0002_joinourconversationpage.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.7 on 2024-07-17 22:31 + +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'), + ('misc', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='JoinOurConversationPage', + 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/misc/migrations/0003_joinourconversationpage_black_box_link_text_and_more.py b/app/misc/migrations/0003_joinourconversationpage_black_box_link_text_and_more.py new file mode 100644 index 0000000..f2d3c99 --- /dev/null +++ b/app/misc/migrations/0003_joinourconversationpage_black_box_link_text_and_more.py @@ -0,0 +1,68 @@ +# Generated by Django 4.2.7 on 2024-07-17 22:38 + +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'), + ('misc', '0002_joinourconversationpage'), + ] + + operations = [ + migrations.AddField( + model_name='joinourconversationpage', + name='black_box_link_text', + field=models.CharField(default='Community Contact'), + ), + migrations.AddField( + model_name='joinourconversationpage', + name='black_box_title', + field=models.CharField(default='Contact a mapping community'), + ), + migrations.AddField( + model_name='joinourconversationpage', + name='code_of_conduct_link_text', + field=models.CharField(default='Code of Conduct'), + ), + migrations.AddField( + model_name='joinourconversationpage', + name='code_of_conduct_title', + field=models.CharField(default='Please read our Code of Conduct'), + ), + migrations.AddField( + model_name='joinourconversationpage', + name='get_connected_blocks', + field=wagtail.fields.StreamField([('blocks', wagtail.blocks.StructBlock([('icon', wagtail.images.blocks.ImageChooserBlock()), ('title', wagtail.blocks.CharBlock()), ('description', wagtail.blocks.RichTextBlock())]))], blank=True, help_text='Blocks to be shown under the Get Connected section.', null=True, use_json_field=True), + ), + migrations.AddField( + model_name='joinourconversationpage', + name='get_connected_title', + field=models.CharField(default='Get Connected!'), + ), + migrations.AddField( + model_name='joinourconversationpage', + 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='joinourconversationpage', + name='intro', + field=wagtail.fields.RichTextField(blank=True, help_text='This is shown in the header.'), + ), + migrations.AddField( + model_name='joinourconversationpage', + name='red_box_link_text', + field=models.CharField(default='Working Groups'), + ), + migrations.AddField( + model_name='joinourconversationpage', + name='red_box_title', + field=models.CharField(default='Join a working group'), + ), + ] diff --git a/app/misc/migrations/0004_joinourconversationpage_code_of_conduct_link_url.py b/app/misc/migrations/0004_joinourconversationpage_code_of_conduct_link_url.py new file mode 100644 index 0000000..1301422 --- /dev/null +++ b/app/misc/migrations/0004_joinourconversationpage_code_of_conduct_link_url.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2024-07-17 22:41 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('misc', '0003_joinourconversationpage_black_box_link_text_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='joinourconversationpage', + name='code_of_conduct_link_url', + field=wagtail.fields.StreamField([('page', wagtail.blocks.PageChooserBlock()), ('url', wagtail.blocks.URLBlock())], blank=True, use_json_field=True), + ), + ] diff --git a/app/misc/migrations/0005_joinourconversationpage_black_box_link_url_and_more.py b/app/misc/migrations/0005_joinourconversationpage_black_box_link_url_and_more.py new file mode 100644 index 0000000..6ff83dc --- /dev/null +++ b/app/misc/migrations/0005_joinourconversationpage_black_box_link_url_and_more.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.7 on 2024-07-17 22:42 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('misc', '0004_joinourconversationpage_code_of_conduct_link_url'), + ] + + operations = [ + migrations.AddField( + model_name='joinourconversationpage', + name='black_box_link_url', + field=wagtail.fields.StreamField([('page', wagtail.blocks.PageChooserBlock()), ('url', wagtail.blocks.URLBlock())], blank=True, use_json_field=True), + ), + migrations.AddField( + model_name='joinourconversationpage', + name='red_box_link_url', + field=wagtail.fields.StreamField([('page', wagtail.blocks.PageChooserBlock()), ('url', wagtail.blocks.URLBlock())], blank=True, use_json_field=True), + ), + ] diff --git a/app/misc/migrations/__init__.py b/app/misc/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/misc/models.py b/app/misc/models.py new file mode 100644 index 0000000..b4b6bfa --- /dev/null +++ b/app/misc/models.py @@ -0,0 +1,95 @@ +from django.db import models + +from wagtail.admin.panels import FieldPanel, MultiFieldPanel +from wagtail.fields import RichTextField, StreamField +from wagtail.blocks import CharBlock, StreamBlock, StructBlock, URLBlock, RichTextBlock, PageChooserBlock +from wagtail.images.blocks import ImageChooserBlock +from wagtail.models import Page +from app.core.models import LinkOrPageBlock + + +class JoinOurConversationPage(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, help_text="This is shown in the header.") + + get_connected_title = models.CharField(default="Get Connected!") + get_connected_blocks = StreamField([ + ('blocks', StructBlock([ + ('icon', ImageChooserBlock()), + ('title', CharBlock()), + ('description', RichTextBlock()) + ])) + ], max_num=3, use_json_field=True, null=True, blank=True, help_text="Blocks to be shown under the Get Connected section.") + + code_of_conduct_title = models.CharField(default="Please read our Code of Conduct") + code_of_conduct_link_text = models.CharField(default="Code of Conduct") + code_of_conduct_link_url = StreamField(LinkOrPageBlock(), use_json_field=True, blank=True) + + red_box_title = models.CharField(default="Join a working group") + red_box_link_text = models.CharField(default="Working Groups") + red_box_link_url = StreamField(LinkOrPageBlock(), use_json_field=True, blank=True) + black_box_title = models.CharField(default="Contact a mapping community") + black_box_link_text = models.CharField(default="Community Contact") + black_box_link_url = StreamField(LinkOrPageBlock(), use_json_field=True, blank=True) + + content_panels = Page.content_panels + [ + FieldPanel('header_image'), + FieldPanel('intro'), + FieldPanel('get_connected_title'), + FieldPanel('get_connected_blocks'), + MultiFieldPanel([ + FieldPanel('code_of_conduct_title'), + FieldPanel('code_of_conduct_link_text'), + FieldPanel('code_of_conduct_link_url'), + ], heading="Code of Conduct"), + 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="Dogear Boxes"), + ] + + +class WorkingGroupLinkBlock(StructBlock): + text = CharBlock() + link = URLBlock(required=False) + + +class WorkingGroupBlock(StructBlock): + title = CharBlock() + description = RichTextBlock() + links = StreamBlock([('link', WorkingGroupLinkBlock())]) + + +class WorkingGroupsPage(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, help_text="This is shown in the header.") + + working_groups = StreamField([('working_group', WorkingGroupBlock())], use_json_field=True, null=True, blank=True) + + content_panels = Page.content_panels + [ + FieldPanel('header_image'), + FieldPanel('intro'), + FieldPanel('working_groups'), + ] diff --git a/app/misc/templates/misc/join_our_conversation_page.html b/app/misc/templates/misc/join_our_conversation_page.html new file mode 100644 index 0000000..dcd5031 --- /dev/null +++ b/app/misc/templates/misc/join_our_conversation_page.html @@ -0,0 +1,46 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-workinggroupspage{% 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 %} + +
+
+ {% include "ui/components/SectionHeadingWithUnderline.html" with title=page.get_connected_title %} +
+ {% for block in page.get_connected_blocks %} +
+ {% image block.value.icon original class="h-8 w-8 mt-2" %} +

+ {{block.value.title}} +

+
+ {{block.value.description}} +
+
+ {% endfor %} +
+ +
+ {% include "ui/components/dogear_boxes/DogearAnyColourLong.html" with colour="var(--hot-off-white)" title=page.code_of_conduct_title linktext=page.code_of_conduct_link_text linkurl=page.code_of_conduct_link_url %} +
+ +
+
+ {% 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/misc/templates/misc/working_groups_page.html b/app/misc/templates/misc/working_groups_page.html new file mode 100644 index 0000000..ef02579 --- /dev/null +++ b/app/misc/templates/misc/working_groups_page.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-workinggroupspage{% 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 %} + +
+
+ {% for group in page.working_groups %} +
+ {% include "ui/components/sections/LinkListSection.html" with title=group.value.title description=group.value.description links=group.value.links external_style=True %} +
+ {% endfor %} +
+
+{% endblock %} diff --git a/app/misc/tests.py b/app/misc/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/app/misc/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/app/misc/views.py b/app/misc/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/app/misc/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/app/ui/templates/ui/components/BaseLink.html b/app/ui/templates/ui/components/BaseLink.html index f609309..2321ff3 100644 --- a/app/ui/templates/ui/components/BaseLink.html +++ b/app/ui/templates/ui/components/BaseLink.html @@ -6,7 +6,7 @@ this is optional, and defaults to the HOT red {% endcomment %} - + {{ linktext }} diff --git a/app/ui/templates/ui/components/PageOrLinkHrefText.html b/app/ui/templates/ui/components/PageOrLinkHrefText.html new file mode 100644 index 0000000..a09453a --- /dev/null +++ b/app/ui/templates/ui/components/PageOrLinkHrefText.html @@ -0,0 +1,11 @@ +{% if linkurl.0 and linkurl.0.value %} + {% if linkurl.0.value.page %} + {{linkurl.0.value.page.url}} + {% elif linkurl.0.value.url %} + {{linkurl.0.value.url}} + {% endif %} +{% else %} + {% if linkurl %} + {{ linkurl }} + {% endif %} +{% endif %} \ No newline at end of file diff --git a/app/ui/templates/ui/components/dogear_boxes/DogearAnyColourLong.html b/app/ui/templates/ui/components/dogear_boxes/DogearAnyColourLong.html index b1f5fdd..2271609 100644 --- a/app/ui/templates/ui/components/dogear_boxes/DogearAnyColourLong.html +++ b/app/ui/templates/ui/components/dogear_boxes/DogearAnyColourLong.html @@ -11,7 +11,7 @@

{{ title }}

-
+ {{ linktext }} {% include "ui/components/icon_svgs/LinkCaret.html" %} diff --git a/app/ui/templates/ui/components/dogear_boxes/DogearContent.html b/app/ui/templates/ui/components/dogear_boxes/DogearContent.html index ca842a1..2b04df7 100644 --- a/app/ui/templates/ui/components/dogear_boxes/DogearContent.html +++ b/app/ui/templates/ui/components/dogear_boxes/DogearContent.html @@ -15,7 +15,7 @@

{% if description %}

{{description|safe}}

{% endif %} -
+

{{ linktext }} + + + + + diff --git a/app/ui/templates/ui/components/sections/LinkListSection.html b/app/ui/templates/ui/components/sections/LinkListSection.html index c2326d9..97e2caf 100644 --- a/app/ui/templates/ui/components/sections/LinkListSection.html +++ b/app/ui/templates/ui/components/sections/LinkListSection.html @@ -7,13 +7,20 @@

{{title}}


-
+
{{description|safe}}
diff --git a/home/migrations/0031_homepage_e404_description_homepage_e404_links_and_more.py b/home/migrations/0031_homepage_e404_description_homepage_e404_links_and_more.py new file mode 100644 index 0000000..1f96321 --- /dev/null +++ b/home/migrations/0031_homepage_e404_description_homepage_e404_links_and_more.py @@ -0,0 +1,30 @@ +# Generated by Django 4.2.7 on 2024-07-17 21:19 + +from django.db import migrations, models +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('home', '0030_homepage_navigation_buttons_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='homepage', + name='e404_description', + field=models.CharField(default="We're sorry, the page you requested could not be found."), + ), + migrations.AddField( + model_name='homepage', + name='e404_links', + field=wagtail.fields.StreamField([('link', wagtail.blocks.StructBlock([('text', wagtail.blocks.CharBlock()), ('url', wagtail.blocks.URLBlock(required=False))]))], blank=True, help_text='Links to be shown on the 404 page.', null=True, use_json_field=True), + ), + migrations.AddField( + model_name='homepage', + name='e404_title', + field=models.CharField(default='Page not found'), + ), + ] diff --git a/home/migrations/0032_alter_homepage_e404_links.py b/home/migrations/0032_alter_homepage_e404_links.py new file mode 100644 index 0000000..25a9c7e --- /dev/null +++ b/home/migrations/0032_alter_homepage_e404_links.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2024-07-17 21:48 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('home', '0031_homepage_e404_description_homepage_e404_links_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='homepage', + name='e404_links', + field=wagtail.fields.StreamField([('link', wagtail.blocks.StructBlock([('text', wagtail.blocks.CharBlock()), ('url', wagtail.blocks.CharBlock(required=False))]))], blank=True, help_text='Links to be shown on the 404 page.', null=True, use_json_field=True), + ), + ] diff --git a/home/models.py b/home/models.py index 8b2da06..c252a63 100644 --- a/home/models.py +++ b/home/models.py @@ -80,6 +80,16 @@ def get_context(self, request, *args, **kwargs): ('url', URLBlock(required=False)) ])) ], use_json_field=True, null=True, blank=True, help_text="The links which show in the bottom right corner of the footer; Privacy Policy, Terms and Conditions, etc.") + + # 404 page + e404_title = models.CharField(default="Page not found") + e404_description = models.CharField(default="We're sorry, the page you requested could not be found.") + e404_links = StreamField([ + ('link', StructBlock([ + ('text', CharBlock()), + ('url', CharBlock(required=False)) + ])) + ], use_json_field=True, null=True, blank=True, help_text="Links to be shown on the 404 page.") # Hero section image = models.ForeignKey( @@ -206,12 +216,19 @@ def get_context(self, request, *args, **kwargs): content_panels = Page.content_panels + [ MultiFieldPanel([ - FieldPanel('navigation'), - FieldPanel('navigation_buttons'), - FieldPanel('footer_candid_seal'), - FieldPanel('footer_bottom_copyright'), - FieldPanel('footer_bottom_links'), - ], heading="Navigation"), + MultiFieldPanel([ + FieldPanel('navigation'), + FieldPanel('navigation_buttons'), + FieldPanel('footer_candid_seal'), + FieldPanel('footer_bottom_copyright'), + FieldPanel('footer_bottom_links'), + ], heading="Navigation"), + MultiFieldPanel([ + FieldPanel('e404_title'), + FieldPanel('e404_description'), + FieldPanel('e404_links'), + ], heading="404 Page"), + ], heading="Universal items"), MultiFieldPanel([ FieldPanel("image"), FieldPanel("hero_text"), diff --git a/home/templates/home/components/404Content.html b/home/templates/home/components/404Content.html new file mode 100644 index 0000000..e045c80 --- /dev/null +++ b/home/templates/home/components/404Content.html @@ -0,0 +1,12 @@ +{% load homepage_tags %} +{% get_home_page as home_page %} + +

{{home_page.e404_title}}

+

{{home_page.e404_description}}

+
+ {% for link in home_page.e404_links %} +

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

+ {% endfor %} +
\ No newline at end of file diff --git a/home/templatetags/homepage_tags.py b/home/templatetags/homepage_tags.py index 8afc110..16500eb 100644 --- a/home/templatetags/homepage_tags.py +++ b/home/templatetags/homepage_tags.py @@ -13,6 +13,11 @@ def get_home_page(context): return None home_page = current_page.get_ancestors(inclusive=True).type(HomePage).first().specific + + if not home_page: + home_page = HomePage.objects.live().filter(locale=context['page'].locale).first().specific + + print(home_page) return home_page diff --git a/hot_osm/settings/base.py b/hot_osm/settings/base.py index 946516b..dcb9101 100644 --- a/hot_osm/settings/base.py +++ b/hot_osm/settings/base.py @@ -50,6 +50,7 @@ "app.search_page", "app.volunteer_opportunities", "app.rfp", + "app.misc", "search", "users", "utils", diff --git a/hot_osm/templates/404.html b/hot_osm/templates/404.html index 0bf5b3b..256e653 100644 --- a/hot_osm/templates/404.html +++ b/hot_osm/templates/404.html @@ -1,4 +1,8 @@ {% extends "base.html" %} + +{% load homepage_tags %} +{% get_home_page as home_page %} + {% block title %} Page not found {% endblock title %} @@ -6,6 +10,8 @@ template-404 {% endblock body_class %} {% block content %} -

Page not found

-

Sorry, this page could not be found.

-{% endblock content %} +
+

404

+ {% include "home/components/404Content.html" %} +
+{% endblock content %} \ No newline at end of file