From 01791ccbc5e9fba8dc058eec6b7781f718c0b0f1 Mon Sep 17 00:00:00 2001 From: nickmoreton Date: Sun, 6 Oct 2024 22:38:40 +0100 Subject: [PATCH 01/20] Implement pico styling --- app/home/templatetags/__init__.py | 0 app/home/templatetags/navigation_tags.py | 10 ++++++++++ app/templates/base.html | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 app/home/templatetags/__init__.py create mode 100644 app/home/templatetags/navigation_tags.py diff --git a/app/home/templatetags/__init__.py b/app/home/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/home/templatetags/navigation_tags.py b/app/home/templatetags/navigation_tags.py new file mode 100644 index 0000000..c6e6309 --- /dev/null +++ b/app/home/templatetags/navigation_tags.py @@ -0,0 +1,10 @@ +from django import template + +from app.blog.models import BlogIndexPage + +register = template.Library() + + +@register.simple_tag +def get_blog_index_url(): + return BlogIndexPage.objects.first().url diff --git a/app/templates/base.html b/app/templates/base.html index 0d550de..d2a83db 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -1,4 +1,4 @@ -{% load static wagtailcore_tags wagtailuserbar blog_tags %} +{% load static wagtailcore_tags wagtailuserbar navigation_tags blog_tags %} From 2482b232cc34080653956e15d291d8cdfa4ec305 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sun, 15 Dec 2024 12:27:18 +0000 Subject: [PATCH 02/20] Remove pico styles --- static_src/scss/app.scss | 89 +++++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 10 deletions(-) diff --git a/static_src/scss/app.scss b/static_src/scss/app.scss index 63ebb17..f6666ce 100644 --- a/static_src/scss/app.scss +++ b/static_src/scss/app.scss @@ -1,13 +1,82 @@ -@use '../../node_modules/@picocss/pico/scss/pico.scss' with ( - $theme-color: "pumpkin", - ); +// @use '../../node_modules/@picocss/pico/scss/pico.scss' with ( +// $theme-color: "pumpkin", +// ); -// The below line are optional, -// you can use it if you want to use the color utility classes -// otherwise they can be removed to save some bytes -@use '../../node_modules/@picocss/pico/scss/colors' as *; -@use "../../node_modules/@picocss/pico/scss/colors/utilities"; +// // The below line are optional, +// // you can use it if you want to use the color utility classes +// // otherwise they can be removed to save some bytes +// @use '../../node_modules/@picocss/pico/scss/colors' as *; +// @use "../../node_modules/@picocss/pico/scss/colors/utilities"; -// Your custom styles goes here -@use 'components/example'; +// // Your custom styles goes here +// @use 'components/example'; + +/** +* Temproary styles for the tutorial +*/ +*, +::before, +::after { + box-sizing: border-box; +} + +html { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, Roboto, "Helvetica Neue", Arial, sans-serif, Apple Color Emoji, "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; +} + +body { + min-height: 100vh; + max-width: 800px; + margin: 0 auto; + padding: 10px; + display: grid; + gap: 3vw; + grid-template-rows: min-content 1fr min-content; +} + +a { + color: currentColor; +} + +footer { + border-top: 2px dotted; + text-align: center; +} + +header { + border-bottom: 2px dotted; +} + +.template-homepage main { + text-align: center; +} + +// Skip link styles +.skip-link { + position: absolute; + top: -30px; +} + +.skip-link:focus-visible { + top: 5px; +} + +// Page form styles +.page-form label { + display: block; + margin-top: 10px; + margin-bottom: 5px; +} + +.page-form :is(textarea, input, select) { + width: 100%; + max-width: 500px; + min-height: 40px; + margin-top: 5px; + margin-bottom: 10px; +} + +.page-form .helptext { + font-style: italic; +} From a32eeff0b78b231eee9fc6739f4201b347db5e12 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sat, 14 Dec 2024 17:14:18 +0000 Subject: [PATCH 03/20] Customise the home page --- .../migrations/0004_customise_home_page.py | 60 +++++++++++++++++++ app/home/models.py | 39 +++++++++++- app/home/templates/home/home_page.html | 22 ++++--- 3 files changed, 111 insertions(+), 10 deletions(-) create mode 100644 app/home/migrations/0004_customise_home_page.py diff --git a/app/home/migrations/0004_customise_home_page.py b/app/home/migrations/0004_customise_home_page.py new file mode 100644 index 0000000..5b1ee9d --- /dev/null +++ b/app/home/migrations/0004_customise_home_page.py @@ -0,0 +1,60 @@ +# Generated by Django 5.1.4 on 2024-12-14 17:13 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("home", "0003_homepage_body"), + ("wagtailcore", "0094_alter_page_locale"), + ("wagtailimages", "0027_image_description"), + ] + + operations = [ + migrations.AddField( + model_name="homepage", + name="hero_cta", + field=models.CharField( + blank=True, + help_text="Text to display on Call to Action", + max_length=255, + verbose_name="Hero CTA", + ), + ), + migrations.AddField( + model_name="homepage", + name="hero_cta_link", + field=models.ForeignKey( + blank=True, + help_text="Choose a page to link to for the Call to Action", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailcore.page", + verbose_name="Hero CTA link", + ), + ), + migrations.AddField( + model_name="homepage", + name="hero_text", + field=models.CharField( + blank=True, + help_text="Write an introduction for the site", + max_length=255, + ), + ), + migrations.AddField( + model_name="homepage", + name="image", + field=models.ForeignKey( + blank=True, + help_text="Homepage image", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailimages.image", + ), + ), + ] diff --git a/app/home/models.py b/app/home/models.py index fe0adbe..7527f15 100644 --- a/app/home/models.py +++ b/app/home/models.py @@ -1,11 +1,48 @@ -from wagtail.admin.panels import FieldPanel +from django.db import models +from wagtail.admin.panels import FieldPanel, MultiFieldPanel from wagtail.fields import RichTextField from wagtail.models import Page class HomePage(Page): + image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="Homepage image", + ) + hero_text = models.CharField( + blank=True, max_length=255, help_text="Write an introduction for the site" + ) + hero_cta = models.CharField( + blank=True, + verbose_name="Hero CTA", + max_length=255, + help_text="Text to display on Call to Action", + ) + hero_cta_link = models.ForeignKey( + "wagtailcore.Page", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + verbose_name="Hero CTA link", + help_text="Choose a page to link to for the Call to Action", + ) + body = RichTextField(blank=True) content_panels = Page.content_panels + [ + MultiFieldPanel( + [ + FieldPanel("image"), + FieldPanel("hero_text"), + FieldPanel("hero_cta"), + FieldPanel("hero_cta_link"), + ], + heading="Hero section", + ), FieldPanel("body"), ] diff --git a/app/home/templates/home/home_page.html b/app/home/templates/home/home_page.html index 86b072e..505c8d7 100644 --- a/app/home/templates/home/home_page.html +++ b/app/home/templates/home/home_page.html @@ -1,15 +1,19 @@ {% extends "base.html" %} - -{% load wagtailcore_tags %} +{% load wagtailcore_tags wagtailimages_tags %} {% block body_class %}template-homepage{% endblock %} {% block content %} -
- {% if page.body %} - {{ page.body|richtext }} - {% else %} -

No content has been added to this page body yet.

+
+

{{ page.title }}

+ {% image page.image fill-480x320 %} +

{{ page.hero_text }}

+ {% if page.hero_cta_link %} + + {% firstof page.hero_cta page.hero_cta_link.title %} + {% endif %} -
-{% endblock %} + + + {{ page.body|richtext }} +{% endblock content %} From ffdddd42b510127e4149e07181ea1fc64c808249 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sat, 14 Dec 2024 17:34:10 +0000 Subject: [PATCH 04/20] Create footer for all pages --- app/base/__init__.py | 0 app/base/apps.py | 6 + app/base/migrations/0001_create_footer.py | 152 ++++++++++++++++++ app/base/migrations/__init__.py | 0 app/base/models.py | 58 +++++++ .../templates/base/includes/footer_text.html | 5 + app/base/templatetags/__init__.py | 0 app/base/templatetags/navigation_tags.py | 18 +++ app/settings/base.py | 5 +- app/templates/base.html | 4 +- app/templates/includes/footer.html | 24 +++ 11 files changed, 268 insertions(+), 4 deletions(-) create mode 100644 app/base/__init__.py create mode 100644 app/base/apps.py create mode 100644 app/base/migrations/0001_create_footer.py create mode 100644 app/base/migrations/__init__.py create mode 100644 app/base/models.py create mode 100644 app/base/templates/base/includes/footer_text.html create mode 100644 app/base/templatetags/__init__.py create mode 100644 app/base/templatetags/navigation_tags.py create mode 100644 app/templates/includes/footer.html diff --git a/app/base/__init__.py b/app/base/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/base/apps.py b/app/base/apps.py new file mode 100644 index 0000000..141b278 --- /dev/null +++ b/app/base/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class BaseConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "app.base" diff --git a/app/base/migrations/0001_create_footer.py b/app/base/migrations/0001_create_footer.py new file mode 100644 index 0000000..585c65c --- /dev/null +++ b/app/base/migrations/0001_create_footer.py @@ -0,0 +1,152 @@ +# Generated by Django 5.1.4 on 2024-12-14 17:23 + +import uuid + +import django.db.models.deletion +import wagtail.fields +import wagtail.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("wagtailcore", "0094_alter_page_locale"), + ] + + operations = [ + migrations.CreateModel( + name="NavigationSettings", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "linkedin_url", + models.URLField(blank=True, verbose_name="LinkedIn URL"), + ), + ("github_url", models.URLField(blank=True, verbose_name="GitHub URL")), + ( + "mastodon_url", + models.URLField(blank=True, verbose_name="Mastodon URL"), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="FooterText", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "translation_key", + models.UUIDField(default=uuid.uuid4, editable=False), + ), + ( + "live", + models.BooleanField( + default=True, editable=False, verbose_name="live" + ), + ), + ( + "has_unpublished_changes", + models.BooleanField( + default=False, + editable=False, + verbose_name="has unpublished changes", + ), + ), + ( + "first_published_at", + models.DateTimeField( + blank=True, + db_index=True, + null=True, + verbose_name="first published at", + ), + ), + ( + "last_published_at", + models.DateTimeField( + editable=False, null=True, verbose_name="last published at" + ), + ), + ( + "go_live_at", + models.DateTimeField( + blank=True, null=True, verbose_name="go live date/time" + ), + ), + ( + "expire_at", + models.DateTimeField( + blank=True, null=True, verbose_name="expiry date/time" + ), + ), + ( + "expired", + models.BooleanField( + default=False, editable=False, verbose_name="expired" + ), + ), + ("body", wagtail.fields.RichTextField()), + ( + "latest_revision", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailcore.revision", + verbose_name="latest revision", + ), + ), + ( + "live_revision", + models.ForeignKey( + blank=True, + editable=False, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailcore.revision", + verbose_name="live revision", + ), + ), + ( + "locale", + models.ForeignKey( + editable=False, + on_delete=django.db.models.deletion.PROTECT, + related_name="+", + to="wagtailcore.locale", + verbose_name="locale", + ), + ), + ], + options={ + "verbose_name_plural": "Footer Text", + "abstract": False, + "unique_together": {("translation_key", "locale")}, + }, + bases=(wagtail.models.PreviewableMixin, models.Model), + ), + ] diff --git a/app/base/migrations/__init__.py b/app/base/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/base/models.py b/app/base/models.py new file mode 100644 index 0000000..9bf0966 --- /dev/null +++ b/app/base/models.py @@ -0,0 +1,58 @@ +from django.db import models +from wagtail.admin.panels import FieldPanel, MultiFieldPanel, PublishingPanel +from wagtail.contrib.settings.models import BaseGenericSetting, register_setting +from wagtail.fields import RichTextField +from wagtail.models import ( + DraftStateMixin, + PreviewableMixin, + RevisionMixin, + TranslatableMixin, +) +from wagtail.snippets.models import register_snippet + + +@register_setting +class NavigationSettings(BaseGenericSetting): + linkedin_url = models.URLField(verbose_name="LinkedIn URL", blank=True) + github_url = models.URLField(verbose_name="GitHub URL", blank=True) + mastodon_url = models.URLField(verbose_name="Mastodon URL", blank=True) + + panels = [ + MultiFieldPanel( + [ + FieldPanel("linkedin_url"), + FieldPanel("github_url"), + FieldPanel("mastodon_url"), + ], + "Social settings", + ) + ] + + +@register_snippet +class FooterText( + DraftStateMixin, + RevisionMixin, + PreviewableMixin, + TranslatableMixin, + models.Model, +): + + body = RichTextField() + + panels = [ + FieldPanel("body"), + PublishingPanel(), + ] + + def __str__(self): + return "Footer text" + + def get_preview_template(self, request, mode_name): + return "base.html" + + def get_preview_context(self, request, mode_name): + return {"footer_text": self.body} + + class Meta(TranslatableMixin.Meta): + verbose_name_plural = "Footer Text" diff --git a/app/base/templates/base/includes/footer_text.html b/app/base/templates/base/includes/footer_text.html new file mode 100644 index 0000000..a536e26 --- /dev/null +++ b/app/base/templates/base/includes/footer_text.html @@ -0,0 +1,5 @@ +{% load wagtailcore_tags %} + +
+ {{ footer_text|richtext }} +
diff --git a/app/base/templatetags/__init__.py b/app/base/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/base/templatetags/navigation_tags.py b/app/base/templatetags/navigation_tags.py new file mode 100644 index 0000000..ef3b3ac --- /dev/null +++ b/app/base/templatetags/navigation_tags.py @@ -0,0 +1,18 @@ +from django import template + +from app.base.models import FooterText + +register = template.Library() + + +@register.inclusion_tag("base/includes/footer_text.html", takes_context=True) +def get_footer_text(context): + footer_text = context.get("footer_text", "") + + if not footer_text: + instance = FooterText.objects.filter(live=True).first() + footer_text = instance.body if instance else "" + + return { + "footer_text": footer_text, + } diff --git a/app/settings/base.py b/app/settings/base.py index c85d76a..1315723 100644 --- a/app/settings/base.py +++ b/app/settings/base.py @@ -25,11 +25,13 @@ # Application definition INSTALLED_APPS = [ + "app.base", + "app.blog", "app.home", "app.search", - "app.blog", "wagtail.contrib.forms", "wagtail.contrib.redirects", + "wagtail.contrib.settings", "wagtail.contrib.table_block", "wagtail.embeds", "wagtail.sites", @@ -76,6 +78,7 @@ "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", + "wagtail.contrib.settings.context_processors.settings", ], }, }, diff --git a/app/templates/base.html b/app/templates/base.html index d2a83db..a3dbe23 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -54,9 +54,7 @@ {% block content %}{% endblock %} - + {% include "includes/footer.html" %} {# Global javascript #} diff --git a/app/templates/includes/footer.html b/app/templates/includes/footer.html new file mode 100644 index 0000000..24479f7 --- /dev/null +++ b/app/templates/includes/footer.html @@ -0,0 +1,24 @@ +{% load navigation_tags %} + +
+

Built with Wagtail

+ + {% with linkedin_url=settings.base.NavigationSettings.linkedin_url github_url=settings.base.NavigationSettings.github_url mastodon_url=settings.base.NavigationSettings.mastodon_url %} + {% if linkedin_url or github_url or mastodon_url %} +

+ Follow me on: + {% if github_url %} + GitHub + {% endif %} + {% if linkedin_url %} + LinkedIn + {% endif %} + {% if mastodon_url %} + Mastodon + {% endif %} +

+ {% endif %} + {% endwith %} + + {% get_footer_text %} +
From e988a2e623c302b412e873772c5e0e6e7599a2b1 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sat, 14 Dec 2024 17:37:27 +0000 Subject: [PATCH 05/20] Set up site menu --- app/base/templatetags/navigation_tags.py | 6 ++++++ app/templates/base.html | 16 +--------------- app/templates/includes/header.html | 13 +++++++++++++ 3 files changed, 20 insertions(+), 15 deletions(-) create mode 100644 app/templates/includes/header.html diff --git a/app/base/templatetags/navigation_tags.py b/app/base/templatetags/navigation_tags.py index ef3b3ac..44d887c 100644 --- a/app/base/templatetags/navigation_tags.py +++ b/app/base/templatetags/navigation_tags.py @@ -1,4 +1,5 @@ from django import template +from wagtail.models import Site from app.base.models import FooterText @@ -16,3 +17,8 @@ def get_footer_text(context): return { "footer_text": footer_text, } + + +@register.simple_tag(takes_context=True) +def get_site_root(context): + return Site.find_for_request(context["request"]).root_page diff --git a/app/templates/base.html b/app/templates/base.html index a3dbe23..1f23cc3 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -34,21 +34,7 @@ {% wagtailuserbar %} - {% blog_index_page as blog %} -
- -
+ {% include "includes/header.html" %}
{% block content %}{% endblock %} diff --git a/app/templates/includes/header.html b/app/templates/includes/header.html new file mode 100644 index 0000000..a5c6cab --- /dev/null +++ b/app/templates/includes/header.html @@ -0,0 +1,13 @@ +{% load wagtailcore_tags navigation_tags %} + +
+ {% get_site_root as site_root %} + +
From 98b2853a846bb2e9920b262ba4b9ee3823cb6aae Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sat, 14 Dec 2024 17:44:50 +0000 Subject: [PATCH 06/20] Improve user experience --- app/templates/base.html | 6 ++++-- app/templates/includes/header.html | 15 ++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/templates/base.html b/app/templates/base.html index 1f23cc3..e83bd29 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -23,6 +23,9 @@ {% endif %} + + + {# Global stylesheets #} @@ -32,11 +35,10 @@ - {% wagtailuserbar %} {% include "includes/header.html" %} -
+
{% block content %}{% endblock %}
diff --git a/app/templates/includes/header.html b/app/templates/includes/header.html index a5c6cab..c6b1829 100644 --- a/app/templates/includes/header.html +++ b/app/templates/includes/header.html @@ -1,13 +1,18 @@ -{% load wagtailcore_tags navigation_tags %} +{% load wagtailcore_tags navigation_tags wagtailuserbar %}
+ {% get_site_root as site_root %} + {% wagtailuserbar "top-right" %}
From f3d55a410c3818a0c6c6dd12daa7d4d31b2cbcb4 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sat, 14 Dec 2024 17:54:55 +0000 Subject: [PATCH 07/20] Create a contact page --- app/base/migrations/0002_add_form_page.py | 162 ++++++++++++++++++ app/base/models.py | 39 ++++- app/base/templates/base/form_page.html | 15 ++ .../templates/base/form_page_landing.html | 9 + 4 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 app/base/migrations/0002_add_form_page.py create mode 100644 app/base/templates/base/form_page.html create mode 100644 app/base/templates/base/form_page_landing.html diff --git a/app/base/migrations/0002_add_form_page.py b/app/base/migrations/0002_add_form_page.py new file mode 100644 index 0000000..054ed08 --- /dev/null +++ b/app/base/migrations/0002_add_form_page.py @@ -0,0 +1,162 @@ +# Generated by Django 5.0.9 on 2024-12-14 17:50 + +import django.db.models.deletion +import modelcluster.fields +import wagtail.contrib.forms.models +import wagtail.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("base", "0001_create_footer"), + ("wagtailcore", "0094_alter_page_locale"), + ] + + operations = [ + migrations.CreateModel( + name="FormPage", + 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", + ), + ), + ( + "to_address", + models.CharField( + blank=True, + help_text="Optional - form submissions will be emailed to these addresses. Separate multiple addresses by comma.", # noqa: E501 + max_length=255, + validators=[wagtail.contrib.forms.models.validate_to_address], + verbose_name="to address", + ), + ), + ( + "from_address", + models.EmailField( + blank=True, max_length=255, verbose_name="from address" + ), + ), + ( + "subject", + models.CharField( + blank=True, max_length=255, verbose_name="subject" + ), + ), + ("intro", wagtail.fields.RichTextField(blank=True)), + ("thank_you_text", wagtail.fields.RichTextField(blank=True)), + ], + options={ + "abstract": False, + }, + bases=( + wagtail.contrib.forms.models.FormMixin, + "wagtailcore.page", + models.Model, + ), + ), + migrations.CreateModel( + name="FormField", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "sort_order", + models.IntegerField(blank=True, editable=False, null=True), + ), + ( + "clean_name", + models.CharField( + blank=True, + default="", + help_text="Safe name of the form field, the label converted to ascii_snake_case", + max_length=255, + verbose_name="name", + ), + ), + ( + "label", + models.CharField( + help_text="The label of the form field", + max_length=255, + verbose_name="label", + ), + ), + ( + "field_type", + models.CharField( + choices=[ + ("singleline", "Single line text"), + ("multiline", "Multi-line text"), + ("email", "Email"), + ("number", "Number"), + ("url", "URL"), + ("checkbox", "Checkbox"), + ("checkboxes", "Checkboxes"), + ("dropdown", "Drop down"), + ("multiselect", "Multiple select"), + ("radio", "Radio buttons"), + ("date", "Date"), + ("datetime", "Date/time"), + ("hidden", "Hidden field"), + ], + max_length=16, + verbose_name="field type", + ), + ), + ( + "required", + models.BooleanField(default=True, verbose_name="required"), + ), + ( + "choices", + models.TextField( + blank=True, + help_text="Comma or new line separated list of choices. Only applicable in checkboxes, radio and dropdown.", # noqa: E501 + verbose_name="choices", + ), + ), + ( + "default_value", + models.TextField( + blank=True, + help_text="Default value. Comma or new line separated values supported for checkboxes.", + verbose_name="default value", + ), + ), + ( + "help_text", + models.CharField( + blank=True, max_length=255, verbose_name="help text" + ), + ), + ( + "page", + modelcluster.fields.ParentalKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="form_fields", + to="base.formpage", + ), + ), + ], + options={ + "ordering": ["sort_order"], + "abstract": False, + }, + ), + ] diff --git a/app/base/models.py b/app/base/models.py index 9bf0966..e2b0a75 100644 --- a/app/base/models.py +++ b/app/base/models.py @@ -1,5 +1,14 @@ from django.db import models -from wagtail.admin.panels import FieldPanel, MultiFieldPanel, PublishingPanel +from modelcluster.fields import ParentalKey +from wagtail.admin.panels import ( + FieldPanel, + FieldRowPanel, + InlinePanel, + MultiFieldPanel, + PublishingPanel, +) +from wagtail.contrib.forms.models import AbstractEmailForm, AbstractFormField +from wagtail.contrib.forms.panels import FormSubmissionsPanel from wagtail.contrib.settings.models import BaseGenericSetting, register_setting from wagtail.fields import RichTextField from wagtail.models import ( @@ -56,3 +65,31 @@ def get_preview_context(self, request, mode_name): class Meta(TranslatableMixin.Meta): verbose_name_plural = "Footer Text" + + +class FormField(AbstractFormField): + page = ParentalKey("FormPage", on_delete=models.CASCADE, related_name="form_fields") + + +class FormPage(AbstractEmailForm): + intro = RichTextField(blank=True) + thank_you_text = RichTextField(blank=True) + + content_panels = AbstractEmailForm.content_panels + [ + FormSubmissionsPanel(), + FieldPanel("intro"), + InlinePanel("form_fields", label="Form fields"), + FieldPanel("thank_you_text"), + MultiFieldPanel( + [ + FieldRowPanel( + [ + FieldPanel("from_address"), + FieldPanel("to_address"), + ] + ), + FieldPanel("subject"), + ], + "Email", + ), + ] diff --git a/app/base/templates/base/form_page.html b/app/base/templates/base/form_page.html new file mode 100644 index 0000000..db1fff2 --- /dev/null +++ b/app/base/templates/base/form_page.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} +{% load wagtailcore_tags %} + +{% block body_class %}template-formpage{% endblock %} + +{% block content %} +

{{ page.title }}

+
{{ page.intro|richtext }}
+ +
+ {% csrf_token %} + {{ form.as_div }} + +
+{% endblock content %} diff --git a/app/base/templates/base/form_page_landing.html b/app/base/templates/base/form_page_landing.html new file mode 100644 index 0000000..f4a1c07 --- /dev/null +++ b/app/base/templates/base/form_page_landing.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} +{% load wagtailcore_tags %} + +{% block body_class %}template-formpage{% endblock %} + +{% block content %} +

{{ page.title }}

+
{{ page.thank_you_text|richtext }}
+{% endblock content %} From d58631132c03be776f8dca9cb08a2956ee444c3c Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sun, 15 Dec 2024 12:27:42 +0000 Subject: [PATCH 08/20] allow mailhog email backend --- app/settings/dev.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/settings/dev.py b/app/settings/dev.py index 1ca04f2..3ab230b 100644 --- a/app/settings/dev.py +++ b/app/settings/dev.py @@ -9,8 +9,16 @@ # SECURITY WARNING: define the correct hosts in production! ALLOWED_HOSTS = ["*"] +# CONSOLE email backend EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" +# MAILHOG email backend. +# Testing email with mailhog, the mailhog container is running on port 1025 +# UNCOMENT THE FOLLOWING LINES TO USE MAILHOG +# EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" +# EMAIL_HOST = "mailhog" +# EMAIL_PORT = 1025 + # Remove if not required INSTALLED_APPS += [ # noqa F405 "app.style_guide", From c8bbce6fffb92d79faa68ea63ed7d2fe6988db1b Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sat, 14 Dec 2024 18:12:54 +0000 Subject: [PATCH 09/20] Add a portfolio page --- app/base/blocks.py | 47 +++++++++ .../base/blocks/captioned_image_block.html | 6 ++ .../templates/base/blocks/embed_block.html | 1 + .../templates/base/blocks/heading_block.html | 7 ++ app/portfolio/__init__.py | 0 app/portfolio/apps.py | 6 ++ app/portfolio/blocks.py | 36 +++++++ .../migrations/0001_create_portfolio.py | 96 ++++++++++++++++++ .../migrations/0002_add_more_custom_blocks.py | 99 +++++++++++++++++++ app/portfolio/migrations/__init__.py | 0 app/portfolio/models.py | 20 ++++ .../portfolio/blocks/card_block.html | 8 ++ .../blocks/featured_posts_block.html | 16 +++ .../templates/portfolio/portfolio_page.html | 11 +++ app/settings/base.py | 1 + 15 files changed, 354 insertions(+) create mode 100644 app/base/blocks.py create mode 100644 app/base/templates/base/blocks/captioned_image_block.html create mode 100644 app/base/templates/base/blocks/embed_block.html create mode 100644 app/base/templates/base/blocks/heading_block.html create mode 100644 app/portfolio/__init__.py create mode 100644 app/portfolio/apps.py create mode 100644 app/portfolio/blocks.py create mode 100644 app/portfolio/migrations/0001_create_portfolio.py create mode 100644 app/portfolio/migrations/0002_add_more_custom_blocks.py create mode 100644 app/portfolio/migrations/__init__.py create mode 100644 app/portfolio/models.py create mode 100644 app/portfolio/templates/portfolio/blocks/card_block.html create mode 100644 app/portfolio/templates/portfolio/blocks/featured_posts_block.html create mode 100644 app/portfolio/templates/portfolio/portfolio_page.html diff --git a/app/base/blocks.py b/app/base/blocks.py new file mode 100644 index 0000000..fa0c27f --- /dev/null +++ b/app/base/blocks.py @@ -0,0 +1,47 @@ +from wagtail.blocks import ( + CharBlock, + ChoiceBlock, + RichTextBlock, + StreamBlock, + StructBlock, +) +from wagtail.embeds.blocks import EmbedBlock +from wagtail.images.blocks import ImageBlock + + +class CaptionedImageBlock(StructBlock): + image = ImageBlock(required=True) + caption = CharBlock(required=False) + attribution = CharBlock(required=False) + + class Meta: + icon = "image" + template = "base/blocks/captioned_image_block.html" + + +class HeadingBlock(StructBlock): + heading_text = CharBlock(classname="title", required=True) + size = ChoiceBlock( + choices=[ + ("", "Select a heading size"), + ("h2", "H2"), + ("h3", "H3"), + ("h4", "H4"), + ], + blank=True, + required=False, + ) + + class Meta: + icon = "title" + template = "base/blocks/heading_block.html" + + +class BaseStreamBlock(StreamBlock): + heading_block = HeadingBlock() + paragraph_block = RichTextBlock(icon="pilcrow") + image_block = CaptionedImageBlock() + embed_block = EmbedBlock( + help_text="Insert a URL to embed. For example, https://www.youtube.com/watch?v=SGJFWirQ3ks", + icon="media", + ) diff --git a/app/base/templates/base/blocks/captioned_image_block.html b/app/base/templates/base/blocks/captioned_image_block.html new file mode 100644 index 0000000..a4b1bad --- /dev/null +++ b/app/base/templates/base/blocks/captioned_image_block.html @@ -0,0 +1,6 @@ +{% load wagtailimages_tags %} + +
+ {% image self.image fill-600x338 loading="lazy" %} +
{{ self.caption }} - {{ self.attribution }}
+
diff --git a/app/base/templates/base/blocks/embed_block.html b/app/base/templates/base/blocks/embed_block.html new file mode 100644 index 0000000..e3125de --- /dev/null +++ b/app/base/templates/base/blocks/embed_block.html @@ -0,0 +1 @@ +{{ self }} diff --git a/app/base/templates/base/blocks/heading_block.html b/app/base/templates/base/blocks/heading_block.html new file mode 100644 index 0000000..8405ce5 --- /dev/null +++ b/app/base/templates/base/blocks/heading_block.html @@ -0,0 +1,7 @@ +{% if self.size == 'h2' %} +

{{ self.heading_text }}

+{% elif self.size == 'h3' %} +

{{ self.heading_text }}

+{% elif self.size == 'h4' %} +

{{ self.heading_text }}

+{% endif %} diff --git a/app/portfolio/__init__.py b/app/portfolio/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/portfolio/apps.py b/app/portfolio/apps.py new file mode 100644 index 0000000..390782e --- /dev/null +++ b/app/portfolio/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class PortfolioConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "app.portfolio" diff --git a/app/portfolio/blocks.py b/app/portfolio/blocks.py new file mode 100644 index 0000000..11fd69f --- /dev/null +++ b/app/portfolio/blocks.py @@ -0,0 +1,36 @@ +from wagtail.blocks import ( + CharBlock, + ListBlock, + PageChooserBlock, + RichTextBlock, + StructBlock, +) +from wagtail.images.blocks import ImageBlock + +from app.base.blocks import BaseStreamBlock + + +class CardBlock(StructBlock): + heading = CharBlock() + text = RichTextBlock(features=["bold", "italic", "link"]) + image = ImageBlock(required=False) + + class Meta: + icon = "form" + template = "portfolio/blocks/card_block.html" + + +class FeaturedPostsBlock(StructBlock): + heading = CharBlock() + text = RichTextBlock(features=["bold", "italic", "link"], required=False) + posts = ListBlock(PageChooserBlock(page_type="blog.BlogPage")) + + class Meta: + icon = "folder-open-inverse" + template = "portfolio/blocks/featured_posts_block.html" + + +class PortfolioStreamBlock(BaseStreamBlock): + + card = CardBlock(group="Sections") + featured_posts = FeaturedPostsBlock(group="Sections") diff --git a/app/portfolio/migrations/0001_create_portfolio.py b/app/portfolio/migrations/0001_create_portfolio.py new file mode 100644 index 0000000..c7de119 --- /dev/null +++ b/app/portfolio/migrations/0001_create_portfolio.py @@ -0,0 +1,96 @@ +# Generated by Django 5.1.4 on 2024-12-14 18:02 + +import django.db.models.deletion +import wagtail.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("wagtailcore", "0094_alter_page_locale"), + ] + + operations = [ + migrations.CreateModel( + name="PortfolioPage", + 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", + ), + ), + ( + "body", + wagtail.fields.StreamField( + [ + ("heading_block", 2), + ("paragraph_block", 3), + ("image_block", 6), + ("embed_block", 7), + ], + blank=True, + block_lookup={ + 0: ( + "wagtail.blocks.CharBlock", + (), + {"form_classname": "title", "required": True}, + ), + 1: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "blank": True, + "choices": [ + ("", "Select a heading size"), + ("h2", "H2"), + ("h3", "H3"), + ("h4", "H4"), + ], + "required": False, + }, + ), + 2: ( + "wagtail.blocks.StructBlock", + [[("heading_text", 0), ("size", 1)]], + {}, + ), + 3: ( + "wagtail.blocks.RichTextBlock", + (), + {"icon": "pilcrow"}, + ), + 4: ("wagtail.images.blocks.ImageBlock", [], {}), + 5: ("wagtail.blocks.CharBlock", (), {"required": False}), + 6: ( + "wagtail.blocks.StructBlock", + [[("image", 4), ("caption", 5), ("attribution", 5)]], + {}, + ), + 7: ( + "wagtail.embeds.blocks.EmbedBlock", + (), + { + "help_text": "Insert a URL to embed. For example, https://www.youtube.com/watch?v=SGJFWirQ3ks", # noqa: E501 + "icon": "media", + }, + ), + }, + help_text="Use this section to list your projects and skills.", + ), + ), + ], + options={ + "abstract": False, + }, + bases=("wagtailcore.page",), + ), + ] diff --git a/app/portfolio/migrations/0002_add_more_custom_blocks.py b/app/portfolio/migrations/0002_add_more_custom_blocks.py new file mode 100644 index 0000000..5b88121 --- /dev/null +++ b/app/portfolio/migrations/0002_add_more_custom_blocks.py @@ -0,0 +1,99 @@ +# Generated by Django 5.1.4 on 2024-12-14 18:11 + +import wagtail.fields +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("portfolio", "0001_create_portfolio"), + ] + + operations = [ + migrations.AlterField( + model_name="portfoliopage", + name="body", + field=wagtail.fields.StreamField( + [ + ("heading_block", 2), + ("paragraph_block", 3), + ("image_block", 6), + ("embed_block", 7), + ("card", 10), + ("featured_posts", 14), + ], + blank=True, + block_lookup={ + 0: ( + "wagtail.blocks.CharBlock", + (), + {"form_classname": "title", "required": True}, + ), + 1: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "blank": True, + "choices": [ + ("", "Select a heading size"), + ("h2", "H2"), + ("h3", "H3"), + ("h4", "H4"), + ], + "required": False, + }, + ), + 2: ( + "wagtail.blocks.StructBlock", + [[("heading_text", 0), ("size", 1)]], + {}, + ), + 3: ("wagtail.blocks.RichTextBlock", (), {"icon": "pilcrow"}), + 4: ("wagtail.images.blocks.ImageBlock", [], {}), + 5: ("wagtail.blocks.CharBlock", (), {"required": False}), + 6: ( + "wagtail.blocks.StructBlock", + [[("image", 4), ("caption", 5), ("attribution", 5)]], + {}, + ), + 7: ( + "wagtail.embeds.blocks.EmbedBlock", + (), + { + "help_text": "Insert a URL to embed. For example, https://www.youtube.com/watch?v=SGJFWirQ3ks", # noqa: E501 + "icon": "media", + }, + ), + 8: ("wagtail.blocks.CharBlock", (), {}), + 9: ( + "wagtail.blocks.RichTextBlock", + (), + {"features": ["bold", "italic", "link"]}, + ), + 10: ( + "wagtail.blocks.StructBlock", + [[("heading", 8), ("text", 9), ("image", 4)]], + {"group": "Sections"}, + ), + 11: ( + "wagtail.blocks.RichTextBlock", + (), + {"features": ["bold", "italic", "link"], "required": False}, + ), + 12: ( + "wagtail.blocks.PageChooserBlock", + (), + {"page_type": ["blog.BlogPage"]}, + ), + 13: ("wagtail.blocks.ListBlock", (12,), {}), + 14: ( + "wagtail.blocks.StructBlock", + [[("heading", 8), ("text", 11), ("posts", 13)]], + {"group": "Sections"}, + ), + }, + help_text="Use this section to list your projects and skills.", + ), + ), + ] diff --git a/app/portfolio/migrations/__init__.py b/app/portfolio/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/portfolio/models.py b/app/portfolio/models.py new file mode 100644 index 0000000..b846d48 --- /dev/null +++ b/app/portfolio/models.py @@ -0,0 +1,20 @@ +from wagtail.admin.panels import FieldPanel +from wagtail.fields import StreamField +from wagtail.models import Page + +from app.portfolio.blocks import PortfolioStreamBlock + + +class PortfolioPage(Page): + parent_page_types = ["home.HomePage"] + + body = StreamField( + PortfolioStreamBlock(), + blank=True, + use_json_field=True, + help_text="Use this section to list your projects and skills.", + ) + + content_panels = Page.content_panels + [ + FieldPanel("body"), + ] diff --git a/app/portfolio/templates/portfolio/blocks/card_block.html b/app/portfolio/templates/portfolio/blocks/card_block.html new file mode 100644 index 0000000..3a2e020 --- /dev/null +++ b/app/portfolio/templates/portfolio/blocks/card_block.html @@ -0,0 +1,8 @@ +{% load wagtailcore_tags wagtailimages_tags %} +
+

{{ self.heading }}

+
{{ self.text|richtext }}
+ {% if self.image %} + {% image self.image width-480 %} + {% endif %} +
diff --git a/app/portfolio/templates/portfolio/blocks/featured_posts_block.html b/app/portfolio/templates/portfolio/blocks/featured_posts_block.html new file mode 100644 index 0000000..8b63bb3 --- /dev/null +++ b/app/portfolio/templates/portfolio/blocks/featured_posts_block.html @@ -0,0 +1,16 @@ +{% load wagtailcore_tags %} +
+

{{ self.heading }}

+ {% if self.text %} +

{{ self.text|richtext }}

+ {% endif %} + +
+ {% for page in self.posts %} +
+

{{ page.title }}

+

{{ page.specific.date }}

+
+ {% endfor %} +
+
diff --git a/app/portfolio/templates/portfolio/portfolio_page.html b/app/portfolio/templates/portfolio/portfolio_page.html new file mode 100644 index 0000000..862412a --- /dev/null +++ b/app/portfolio/templates/portfolio/portfolio_page.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + +{% load wagtailcore_tags wagtailimages_tags %} + +{% block body_class %}template-portfolio{% endblock %} + +{% block content %} +

{{ page.title }}

+ + {{ page.body }} +{% endblock %} diff --git a/app/settings/base.py b/app/settings/base.py index 1315723..e428a8c 100644 --- a/app/settings/base.py +++ b/app/settings/base.py @@ -28,6 +28,7 @@ "app.base", "app.blog", "app.home", + "app.portfolio", "app.search", "wagtail.contrib.forms", "wagtail.contrib.redirects", From 37ce1f8ba4db51f1625b2bb0a9989d577bd0c895 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sun, 15 Dec 2024 12:00:44 +0000 Subject: [PATCH 10/20] Add search --- app/search/templates/search/search.html | 12 ++++++++++-- app/templates/includes/header.html | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/search/templates/search/search.html b/app/search/templates/search/search.html index 476427f..3291ae8 100644 --- a/app/search/templates/search/search.html +++ b/app/search/templates/search/search.html @@ -14,7 +14,10 @@

Search

{% if search_results %} -
    + +

    You searched{% if search_query %} for “{{ search_query }}”{% endif %}, {{ search_results.paginator.count }} result{{ search_results.paginator.count|pluralize }} found.

    + +
      {% for result in search_results %}
    1. {{ result }}

      @@ -23,7 +26,11 @@

      {{ result }}

      {% endif %}
    2. {% endfor %} -
+ + +{% if search_results.paginator.num_pages > 1 %} +

Page {{ search_results.number }} of {{ search_results.paginator.num_pages }}, showing {{ search_results|length }} result{{ search_results|pluralize }} out of {{ search_results.paginator.count }}

+{% endif %} {% if search_results.has_previous %} Previous @@ -32,6 +39,7 @@

{{ result }}

{% if search_results.has_next %} Next {% endif %} + {% elif search_query %} No results found {% endif %} diff --git a/app/templates/includes/header.html b/app/templates/includes/header.html index c6b1829..6b436cd 100644 --- a/app/templates/includes/header.html +++ b/app/templates/includes/header.html @@ -12,6 +12,7 @@ {{ menuitem.title }}{% if not forloop.last %} | {% endif %} {% endfor %} + | Search

{% wagtailuserbar "top-right" %} From 6108c57660f87540c1750309e51f283b7bdd6665 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sun, 15 Dec 2024 12:41:38 +0000 Subject: [PATCH 11/20] Add pico styling back With the exceptrion of the skip link styles --- static_src/scss/app.scss | 112 +++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/static_src/scss/app.scss b/static_src/scss/app.scss index f6666ce..6aa3506 100644 --- a/static_src/scss/app.scss +++ b/static_src/scss/app.scss @@ -1,56 +1,56 @@ -// @use '../../node_modules/@picocss/pico/scss/pico.scss' with ( -// $theme-color: "pumpkin", -// ); +@use '../../node_modules/@picocss/pico/scss/pico.scss' with ( + $theme-color: "pumpkin", + ); -// // The below line are optional, -// // you can use it if you want to use the color utility classes -// // otherwise they can be removed to save some bytes -// @use '../../node_modules/@picocss/pico/scss/colors' as *; -// @use "../../node_modules/@picocss/pico/scss/colors/utilities"; +// The below line are optional, +// you can use it if you want to use the color utility classes +// otherwise they can be removed to save some bytes +@use '../../node_modules/@picocss/pico/scss/colors' as *; +@use "../../node_modules/@picocss/pico/scss/colors/utilities"; -// // Your custom styles goes here -// @use 'components/example'; +// Your custom styles goes here +@use 'components/example'; /** * Temproary styles for the tutorial */ -*, -::before, -::after { - box-sizing: border-box; -} +// *, +// ::before, +// ::after { +// box-sizing: border-box; +// } -html { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, Roboto, "Helvetica Neue", Arial, sans-serif, Apple Color Emoji, "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; -} +// html { +// font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, Roboto, "Helvetica Neue", Arial, sans-serif, Apple Color Emoji, "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; +// } -body { - min-height: 100vh; - max-width: 800px; - margin: 0 auto; - padding: 10px; - display: grid; - gap: 3vw; - grid-template-rows: min-content 1fr min-content; -} +// body { +// min-height: 100vh; +// max-width: 800px; +// margin: 0 auto; +// padding: 10px; +// display: grid; +// gap: 3vw; +// grid-template-rows: min-content 1fr min-content; +// } -a { - color: currentColor; -} +// a { +// color: currentColor; +// } -footer { - border-top: 2px dotted; - text-align: center; -} +// footer { +// border-top: 2px dotted; +// text-align: center; +// } -header { - border-bottom: 2px dotted; -} +// header { +// border-bottom: 2px dotted; +// } -.template-homepage main { - text-align: center; -} +// .template-homepage main { +// text-align: center; +// } // Skip link styles .skip-link { @@ -62,21 +62,21 @@ header { top: 5px; } -// Page form styles -.page-form label { - display: block; - margin-top: 10px; - margin-bottom: 5px; -} +// // Page form styles +// .page-form label { +// display: block; +// margin-top: 10px; +// margin-bottom: 5px; +// } -.page-form :is(textarea, input, select) { - width: 100%; - max-width: 500px; - min-height: 40px; - margin-top: 5px; - margin-bottom: 10px; -} +// .page-form :is(textarea, input, select) { +// width: 100%; +// max-width: 500px; +// min-height: 40px; +// margin-top: 5px; +// margin-bottom: 10px; +// } -.page-form .helptext { - font-style: italic; -} +// .page-form .helptext { +// font-style: italic; +// } From d7d8da716fdd9be9cf6d3e0441a7d17965eeac41 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sun, 15 Dec 2024 12:47:16 +0000 Subject: [PATCH 12/20] Apply the container-fluid class to the main, header, and footer elements --- app/templates/base.html | 4 +++- app/templates/includes/footer.html | 38 ++++++++++++++++-------------- app/templates/includes/header.html | 26 ++++++++++---------- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/app/templates/base.html b/app/templates/base.html index e83bd29..14638ff 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -39,7 +39,9 @@ {% include "includes/header.html" %}
- {% block content %}{% endblock %} +
+ {% block content %}{% endblock %} +
{% include "includes/footer.html" %} diff --git a/app/templates/includes/footer.html b/app/templates/includes/footer.html index 24479f7..0843e08 100644 --- a/app/templates/includes/footer.html +++ b/app/templates/includes/footer.html @@ -1,24 +1,26 @@ {% load navigation_tags %}
-

Built with Wagtail

+
+

Built with Wagtail

- {% with linkedin_url=settings.base.NavigationSettings.linkedin_url github_url=settings.base.NavigationSettings.github_url mastodon_url=settings.base.NavigationSettings.mastodon_url %} - {% if linkedin_url or github_url or mastodon_url %} -

- Follow me on: - {% if github_url %} - GitHub - {% endif %} - {% if linkedin_url %} - LinkedIn - {% endif %} - {% if mastodon_url %} - Mastodon - {% endif %} -

- {% endif %} - {% endwith %} + {% with linkedin_url=settings.base.NavigationSettings.linkedin_url github_url=settings.base.NavigationSettings.github_url mastodon_url=settings.base.NavigationSettings.mastodon_url %} + {% if linkedin_url or github_url or mastodon_url %} +

+ Follow me on: + {% if github_url %} + GitHub + {% endif %} + {% if linkedin_url %} + LinkedIn + {% endif %} + {% if mastodon_url %} + Mastodon + {% endif %} +

+ {% endif %} + {% endwith %} - {% get_footer_text %} + {% get_footer_text %} +
diff --git a/app/templates/includes/header.html b/app/templates/includes/header.html index 6b436cd..2e48303 100644 --- a/app/templates/includes/header.html +++ b/app/templates/includes/header.html @@ -1,19 +1,21 @@ {% load wagtailcore_tags navigation_tags wagtailuserbar %}
- - {% get_site_root as site_root %} - + {% wagtailuserbar "top-right" %}
From 465c83182a8bb925f312a65c49783f79ec83a027 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sun, 15 Dec 2024 12:50:36 +0000 Subject: [PATCH 13/20] Hide body content in the blog index page --- app/blog/templates/blog/blog_index_page.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/blog/templates/blog/blog_index_page.html b/app/blog/templates/blog/blog_index_page.html index f208bca..a8f0e76 100644 --- a/app/blog/templates/blog/blog_index_page.html +++ b/app/blog/templates/blog/blog_index_page.html @@ -32,7 +32,9 @@

{{ post.title }}

{% endwith %}

{{ post.intro }}

+ {% comment %} Don't display the body text here {{ post.body|richtext }} + {% endcomment %}
{% endwith %} From f28b0bbc69b4660f741ac7d69df682ec6778c53e Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sun, 15 Dec 2024 22:28:39 +0000 Subject: [PATCH 14/20] Add semantic HTML5 elements to the templates These are styled directy by Pico css, so no need to add any additional css. --- app/base/templates/base/form_page.html | 12 +- app/blog/templates/blog/blog_index_page.html | 75 ++++----- app/blog/templates/blog/blog_page.html | 150 ++++++++++-------- app/home/templates/home/home_page.html | 29 ++-- .../templates/portfolio/portfolio_page.html | 7 +- app/search/templates/search/search.html | 84 +++++----- app/templates/includes/header.html | 9 +- 7 files changed, 210 insertions(+), 156 deletions(-) diff --git a/app/base/templates/base/form_page.html b/app/base/templates/base/form_page.html index db1fff2..d233174 100644 --- a/app/base/templates/base/form_page.html +++ b/app/base/templates/base/form_page.html @@ -4,12 +4,20 @@ {% block body_class %}template-formpage{% endblock %} {% block content %} -

{{ page.title }}

-
{{ page.intro|richtext }}
+ +
+ +
+

{{ page.title }}

+
{{ page.intro|richtext }}
+
{% csrf_token %} {{ form.as_div }}
+ +
+ {% endblock content %} diff --git a/app/blog/templates/blog/blog_index_page.html b/app/blog/templates/blog/blog_index_page.html index a8f0e76..20227cb 100644 --- a/app/blog/templates/blog/blog_index_page.html +++ b/app/blog/templates/blog/blog_index_page.html @@ -5,46 +5,49 @@ {% block body_class %}template-blogindexpage{% endblock %} {% block content %} -
-

{{ page.title }}

-
{{ page.intro|richtext }}
-
- {% for post in blogpages %} +
+

{{ page.title }}

+
{{ page.intro|richtext }}
+
+ +{% for post in blogpages %} + +{% if forloop.first or forloop.counter0|divisibleby:3 %} +{% comment %} Start a new row {% endcomment %} +
+ {% endif %} - {% if forloop.first or forloop.counter0|divisibleby:2 %} - {% comment %} Start a new row {% endcomment %} +
+ {% with post=post.specific %} +
+

{{ post.title }}

+
- {% endif %} - -
- {% with post=post.specific %} -
-

{{ post.title }}

-
-
- {% with post.main_image as main_image %} - {% if main_image %} -
- {% image main_image fill-160x100 %} -
- {% endif %} - {% endwith %} -
-

{{ post.intro }}

- {% comment %} Don't display the body text here - {{ post.body|richtext }} - {% endcomment %} -
-
- {% endwith %} -
- - {% if forloop.last or forloop.counter|divisibleby:2 %} - {% comment %} End the row {% endcomment %} + {% with post.main_image as main_image %} + + {% if main_image %} +
+ {% image main_image fill-160x100 %} +
+ {% endif %} + + {% endwith %} +
+

{{ post.intro }}

+ {% comment %} Don't display the body text here + {{ post.body|richtext }} + {% endcomment %} +
- {% endif %} + {% endwith %} +
+ + {% if forloop.last or forloop.counter|divisibleby:3 %} + {% comment %} End the row {% endcomment %} +
+{% endif %} - {% endfor %} +{% endfor %} {% endblock %} diff --git a/app/blog/templates/blog/blog_page.html b/app/blog/templates/blog/blog_page.html index 9313091..338b5c9 100644 --- a/app/blog/templates/blog/blog_page.html +++ b/app/blog/templates/blog/blog_page.html @@ -6,77 +6,103 @@ {% block content %} -
-
-
-

{{ page.title }}

-

{{ page.date }}

-
+
+ + - -
- {% with authors=page.authors.all %} - {% if authors %} -

Posted by:

- {% for author in authors %} - - {% image author.author_image fill-40x40 as author_image %} - {% if author_image %} - {{ author.name }} - {% else %} - user - {% endif %} - {{ author.name }} - - {% endfor %} - {% endif %} - {% endwith %} -
+ +
+ +
+ Posted by: + {% with authors=page.authors.all %} + + {% if authors %} + + {% for author in authors %} + + {% image author.author_image fill-40x40 as author_image %} + {% if author_image %} + {{ author.name }} + {% else %} + + user + + + + + + {% endif %} + {{ author.name }} + + {% endfor %} + + {% endif %} + + {% endwith %} +
{% blog_tags_page as tags_page %} + {% with tags=page.tags.all %} - {% if tags %} - Tags: - {% if tags_page %} - {% for tag in tags %} - {{ tag }} - {% endfor %} - {% else %} -

Create a blog tags page

- {% endif %} - {% endif %} + + {% if tags %} + + Tags: + + {% if tags_page %} + {% for tag in tags %} + {{ tag }} + {% endfor %} + + {% else %} + +

Create a blog tags page

+ {% endif %} + + {% endif %} + {% endwith %} -
+ +
+ +
+
+ +
+ {{ page.body|richtext }}
-
-
-
-

{{ page.intro }}

- {{ page.body|richtext }} -
- -
- - {% for item in page.gallery_images.all %} - {% if forloop.first or forloop.counter0|divisibleby:3 %} - {% comment %} Start a new row {% endcomment %} -
- {% endif %} -
- {% image item.image fill-600x400 %} -
- {{ item.caption }} -
-
- {% if forloop.last or forloop.counter|divisibleby:3 %} -
- {% endif %} - {% endfor %} + {% for item in page.gallery_images.all %} + + {% if forloop.first or forloop.counter0|divisibleby:4 %} + {% comment %} Start a new row {% endcomment %} +
+ {% endif %} +
+ {% image item.image fill-600x400 %} +
+ {{ item.caption }} +
+
-
+ {% if forloop.last or forloop.counter|divisibleby:4 %} + {% comment %} End row {% endcomment %} + + + {% endif %} + + {% endfor %} + +
{% endblock %} diff --git a/app/home/templates/home/home_page.html b/app/home/templates/home/home_page.html index 505c8d7..c71facc 100644 --- a/app/home/templates/home/home_page.html +++ b/app/home/templates/home/home_page.html @@ -4,16 +4,23 @@ {% block body_class %}template-homepage{% endblock %} {% block content %} -
-

{{ page.title }}

- {% image page.image fill-480x320 %} -

{{ page.hero_text }}

- {% if page.hero_cta_link %} - - {% firstof page.hero_cta page.hero_cta_link.title %} - - {% endif %} -
- {{ page.body|richtext }} +{% image page.image fill-1920x1080 as hero_image %} + + + +
+

{{ page.title }}

+ {{ page.body|richtext }} +
+ {% endblock content %} diff --git a/app/portfolio/templates/portfolio/portfolio_page.html b/app/portfolio/templates/portfolio/portfolio_page.html index 862412a..e2d2e86 100644 --- a/app/portfolio/templates/portfolio/portfolio_page.html +++ b/app/portfolio/templates/portfolio/portfolio_page.html @@ -5,7 +5,10 @@ {% block body_class %}template-portfolio{% endblock %} {% block content %} -

{{ page.title }}

- {{ page.body }} +
+

{{ page.title }}

+ {{ page.body }} +
+ {% endblock %} diff --git a/app/search/templates/search/search.html b/app/search/templates/search/search.html index 3291ae8..f30ba6b 100644 --- a/app/search/templates/search/search.html +++ b/app/search/templates/search/search.html @@ -6,41 +6,49 @@ {% block title %}Search{% endblock %} {% block content %} -

Search

- -
- - -
- -{% if search_results %} - -

You searched{% if search_query %} for “{{ search_query }}”{% endif %}, {{ search_results.paginator.count }} result{{ search_results.paginator.count|pluralize }} found.

- -
    - {% for result in search_results %} -
  1. -

    {{ result }}

    - {% if result.search_description %} - {{ result.search_description }} - {% endif %} -
  2. - {% endfor %} -
- -{% if search_results.paginator.num_pages > 1 %} -

Page {{ search_results.number }} of {{ search_results.paginator.num_pages }}, showing {{ search_results|length }} result{{ search_results|pluralize }} out of {{ search_results.paginator.count }}

-{% endif %} - -{% if search_results.has_previous %} -Previous -{% endif %} - -{% if search_results.has_next %} -Next -{% endif %} - -{% elif search_query %} -No results found -{% endif %} -{% endblock %} + +
+

Search

+
+
+ + +
+
+ + {% if search_results %} + +

You searched{% if search_query %} for “{{ search_query }}”{% endif %}, {{ search_results.paginator.count }} result{{ search_results.paginator.count|pluralize }} found.

+ +
    + {% for result in search_results %} +
  1. + {{ result }} + {% if result.search_description %} + {{ result.search_description }} + {% endif %} +
  2. + {% endfor %} +
+ + {% if search_results.paginator.num_pages > 1 %} +

Page {{ search_results.number }} of {{ search_results.paginator.num_pages }}, showing {{ search_results|length }} result{{ search_results|pluralize }} out of {{ search_results.paginator.count }}

+ {% endif %} + + {% if search_results.has_previous %} + Previous + {% endif %} + + {% if search_results.has_next %} + Next + {% endif %} + + {% elif search_query %} + + No results found + + {% endif %} + + {% endblock %} + +
diff --git a/app/templates/includes/header.html b/app/templates/includes/header.html index 2e48303..b0f8842 100644 --- a/app/templates/includes/header.html +++ b/app/templates/includes/header.html @@ -6,14 +6,13 @@ {% get_site_root as site_root %} From 7dbca732e0ad4ecfc7da541605a686d41164ac9d Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Mon, 16 Dec 2024 11:22:32 +0000 Subject: [PATCH 15/20] Custom navigation styling --- app/home/templates/home/home_page.html | 6 +- app/templates/includes/header.html | 7 ++- static_src/js/app.js | 24 +++---- static_src/scss/app.scss | 73 +--------------------- static_src/scss/components/example.scss | 1 - static_src/scss/components/hero.scss | 37 +++++++++++ static_src/scss/components/navigation.scss | 46 ++++++++++++++ static_src/scss/components/skip-link.scss | 9 +++ static_src/scss/vars.scss | 6 ++ 9 files changed, 116 insertions(+), 93 deletions(-) delete mode 100644 static_src/scss/components/example.scss create mode 100644 static_src/scss/components/hero.scss create mode 100644 static_src/scss/components/navigation.scss create mode 100644 static_src/scss/components/skip-link.scss create mode 100644 static_src/scss/vars.scss diff --git a/app/home/templates/home/home_page.html b/app/home/templates/home/home_page.html index c71facc..7513ec9 100644 --- a/app/home/templates/home/home_page.html +++ b/app/home/templates/home/home_page.html @@ -7,10 +7,8 @@ {% image page.image fill-1920x1080 as hero_image %} -
-

- {{ page.hero_text }} -

+
+ {{ page.hero_text }} {% if page.hero_cta_link %} {% firstof page.hero_cta page.hero_cta_link.title %} diff --git a/app/templates/includes/header.html b/app/templates/includes/header.html index b0f8842..b473c70 100644 --- a/app/templates/includes/header.html +++ b/app/templates/includes/header.html @@ -4,8 +4,9 @@
{% get_site_root as site_root %} -
{% wagtailuserbar "top-right" %} diff --git a/static_src/js/app.js b/static_src/js/app.js index a4ce6c7..02a556e 100644 --- a/static_src/js/app.js +++ b/static_src/js/app.js @@ -1,20 +1,14 @@ -/** - * This is a simple example. - * It will log a message to the console. - * Remove this content and write your scripts as required. - */ -class ShowMessage { - constructor(times=3) { - this.message = 'Hello from Wagtail starter kit!'; - this.times = times; +class Navigation { + constructor() { + this.menu = document.querySelector('[role="navigation"]'); + this.menuButton = this.menu.querySelector('button:first-of-type'); + this.menuButton.addEventListener('click', this.toggleMenu.bind(this)); + console.log('Navigation initialized'); } - showMessage() { - for (let i = 0; i < this.times; i++) { - console.log(this.message); - } + toggleMenu() { + this.menu.classList.toggle('is-open'); } } -const showMessage = new ShowMessage(); -showMessage.showMessage(); +new Navigation(); diff --git a/static_src/scss/app.scss b/static_src/scss/app.scss index 6aa3506..83cfafe 100644 --- a/static_src/scss/app.scss +++ b/static_src/scss/app.scss @@ -10,73 +10,6 @@ // Your custom styles goes here -@use 'components/example'; - -/** -* Temproary styles for the tutorial -*/ -// *, -// ::before, -// ::after { -// box-sizing: border-box; -// } - -// html { -// font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, Roboto, "Helvetica Neue", Arial, sans-serif, Apple Color Emoji, "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; -// } - -// body { -// min-height: 100vh; -// max-width: 800px; -// margin: 0 auto; -// padding: 10px; -// display: grid; -// gap: 3vw; -// grid-template-rows: min-content 1fr min-content; -// } - -// a { -// color: currentColor; -// } - -// footer { -// border-top: 2px dotted; -// text-align: center; -// } - -// header { -// border-bottom: 2px dotted; -// } - -// .template-homepage main { -// text-align: center; -// } - -// Skip link styles -.skip-link { - position: absolute; - top: -30px; -} - -.skip-link:focus-visible { - top: 5px; -} - -// // Page form styles -// .page-form label { -// display: block; -// margin-top: 10px; -// margin-bottom: 5px; -// } - -// .page-form :is(textarea, input, select) { -// width: 100%; -// max-width: 500px; -// min-height: 40px; -// margin-top: 5px; -// margin-bottom: 10px; -// } - -// .page-form .helptext { -// font-style: italic; -// } +@use 'components/skip-link'; +@use 'components/hero'; +@use 'components/navigation'; diff --git a/static_src/scss/components/example.scss b/static_src/scss/components/example.scss deleted file mode 100644 index eb0c546..0000000 --- a/static_src/scss/components/example.scss +++ /dev/null @@ -1 +0,0 @@ -// example imported/used in app.scss diff --git a/static_src/scss/components/hero.scss b/static_src/scss/components/hero.scss new file mode 100644 index 0000000..19a3966 --- /dev/null +++ b/static_src/scss/components/hero.scss @@ -0,0 +1,37 @@ +@use '../vars.scss' as *; + +// Hero styles +[role=hero] { + display: relative; + min-height: 200px; + background-position: bottom; + background-size: cover; + position: relative; + mark { + display: block; + background: transparent; + text-align: center; + font-size: 2rem; + font-weight: bold; + color: white; + text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.5); + } + [role=button] { + position: absolute; + bottom: -10px; + left: 50%; + transform: translateX(-50%); + } + @media screen and (min-width: $sm) { + min-height: 300px; + } + @media screen and (min-width: $md) { + min-height: 400px; + } + @media screen and (min-width: $lg) { + min-height: 500px; + } + @media screen and (min-width: $xl) { + min-height: 600px; + } +} diff --git a/static_src/scss/components/navigation.scss b/static_src/scss/components/navigation.scss new file mode 100644 index 0000000..1ef1935 --- /dev/null +++ b/static_src/scss/components/navigation.scss @@ -0,0 +1,46 @@ +@use '../vars.scss' as *; + +[role=navigation] { + button:first-child { + display: block; + @media screen and (min-width: $md) { + display: none; + } + } + > div { + position: absolute; + z-index: 1; + top: -3px; + left: 100px; + margin-left: -100%; + padding: 20px; + opacity: 0; + background-color: rgba(255, 255, 255, 0.9); + border-radius: 5px; + a[role=button] { + display: block; + margin-bottom: 3px; + } + @media screen and (min-width: $md) { + position: inherit; + top: auto; + left: auto; + margin-left: 0; + padding: 0; + opacity: 1; + background-color: transparent; + border-radius: 0; + a[role=button] { + display: inline-block; + } + } + } + &.is-open { + > div { + margin-left: 0; + opacity: 1; + transition: all 0.3s ease; + } + } + +} diff --git a/static_src/scss/components/skip-link.scss b/static_src/scss/components/skip-link.scss new file mode 100644 index 0000000..1e271ba --- /dev/null +++ b/static_src/scss/components/skip-link.scss @@ -0,0 +1,9 @@ +// Skip link styles +.skip-link { + position: absolute; + top: -30px; +} + +.skip-link:focus-visible { + top: 5px; +} diff --git a/static_src/scss/vars.scss b/static_src/scss/vars.scss new file mode 100644 index 0000000..0db429c --- /dev/null +++ b/static_src/scss/vars.scss @@ -0,0 +1,6 @@ +// Breakpoints +$sm: 576px; +$md: 768px; +$lg: 1024px; +$xl: 1280px; +$xxl: 1536px; From 9028c85a3ca5a3c95ebcab9cadef6915294a6316 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Mon, 16 Dec 2024 16:28:10 +0000 Subject: [PATCH 16/20] Add styling for custom blocks --- app/base/blocks.py | 1 + .../base/blocks/captioned_image_block.html | 11 ++++++---- .../templates/base/blocks/embed_block.html | 6 ++++- .../templates/base/form_page_landing.html | 8 +++++-- .../portfolio/blocks/card_block.html | 4 ++-- .../blocks/featured_posts_block.html | 4 ++-- static_src/scss/app.scss | 1 + static_src/scss/components/embed.scss | 22 +++++++++++++++++++ 8 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 static_src/scss/components/embed.scss diff --git a/app/base/blocks.py b/app/base/blocks.py index fa0c27f..a70ed80 100644 --- a/app/base/blocks.py +++ b/app/base/blocks.py @@ -44,4 +44,5 @@ class BaseStreamBlock(StreamBlock): embed_block = EmbedBlock( help_text="Insert a URL to embed. For example, https://www.youtube.com/watch?v=SGJFWirQ3ks", icon="media", + template="base/blocks/embed_block.html", ) diff --git a/app/base/templates/base/blocks/captioned_image_block.html b/app/base/templates/base/blocks/captioned_image_block.html index a4b1bad..453ed66 100644 --- a/app/base/templates/base/blocks/captioned_image_block.html +++ b/app/base/templates/base/blocks/captioned_image_block.html @@ -1,6 +1,9 @@ {% load wagtailimages_tags %} -
- {% image self.image fill-600x338 loading="lazy" %} -
{{ self.caption }} - {{ self.attribution }}
-
+
+
+ {% image self.image fill-600x338 loading="lazy" %} +
{{ self.caption }} - {{ self.attribution }}
+
+ +
diff --git a/app/base/templates/base/blocks/embed_block.html b/app/base/templates/base/blocks/embed_block.html index e3125de..7e927ba 100644 --- a/app/base/templates/base/blocks/embed_block.html +++ b/app/base/templates/base/blocks/embed_block.html @@ -1 +1,5 @@ -{{ self }} +{% load wagtailembeds_tags %} + +
+ {{ self }} +
diff --git a/app/base/templates/base/form_page_landing.html b/app/base/templates/base/form_page_landing.html index f4a1c07..7d7b85e 100644 --- a/app/base/templates/base/form_page_landing.html +++ b/app/base/templates/base/form_page_landing.html @@ -4,6 +4,10 @@ {% block body_class %}template-formpage{% endblock %} {% block content %} -

{{ page.title }}

-
{{ page.thank_you_text|richtext }}
+
+
+

{{ page.title }}

+
{{ page.thank_you_text|richtext }}
+
+
{% endblock content %} diff --git a/app/portfolio/templates/portfolio/blocks/card_block.html b/app/portfolio/templates/portfolio/blocks/card_block.html index 3a2e020..3f86120 100644 --- a/app/portfolio/templates/portfolio/blocks/card_block.html +++ b/app/portfolio/templates/portfolio/blocks/card_block.html @@ -1,8 +1,8 @@ {% load wagtailcore_tags wagtailimages_tags %} -
+

{{ self.heading }}

{{ self.text|richtext }}
{% if self.image %} {% image self.image width-480 %} {% endif %} -
+
diff --git a/app/portfolio/templates/portfolio/blocks/featured_posts_block.html b/app/portfolio/templates/portfolio/blocks/featured_posts_block.html index 8b63bb3..ae59369 100644 --- a/app/portfolio/templates/portfolio/blocks/featured_posts_block.html +++ b/app/portfolio/templates/portfolio/blocks/featured_posts_block.html @@ -1,5 +1,5 @@ {% load wagtailcore_tags %} -
+

{{ self.heading }}

{% if self.text %}

{{ self.text|richtext }}

@@ -13,4 +13,4 @@

{{ self.heading }}

{% endfor %} - +
diff --git a/static_src/scss/app.scss b/static_src/scss/app.scss index 83cfafe..bfd76e3 100644 --- a/static_src/scss/app.scss +++ b/static_src/scss/app.scss @@ -13,3 +13,4 @@ @use 'components/skip-link'; @use 'components/hero'; @use 'components/navigation'; +@use 'components/embed'; diff --git a/static_src/scss/components/embed.scss b/static_src/scss/components/embed.scss new file mode 100644 index 0000000..da1fd3d --- /dev/null +++ b/static_src/scss/components/embed.scss @@ -0,0 +1,22 @@ +@use '../vars.scss' as *; + +[role=video] { + + > div { + position: relative; + padding-bottom: 420px; + height: 0; + overflow: hidden; + max-width: 720px; + max-height: 420px; + } + + iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } + +} From 7d2d70d57ee728c8cbbde31afd27a5b22ac7449a Mon Sep 17 00:00:00 2001 From: nickmoreton Date: Fri, 15 Aug 2025 15:40:23 +0100 Subject: [PATCH 17/20] Adjust the populate commands --- app/blog/management/commands/populate_blog.py | 1 + app/home/management/commands/populate_homepage.py | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/app/blog/management/commands/populate_blog.py b/app/blog/management/commands/populate_blog.py index bfaf936..e7309a0 100644 --- a/app/blog/management/commands/populate_blog.py +++ b/app/blog/management/commands/populate_blog.py @@ -128,6 +128,7 @@ def create_blog_index(self, home_page): "

Welcome to our blog! Here you'll find the latest news, " "insights, and stories from our team.

" ), + show_in_menus=True, ) home_page.add_child(instance=blog_index) blog_index.save_revision().publish() diff --git a/app/home/management/commands/populate_homepage.py b/app/home/management/commands/populate_homepage.py index 29f39c7..e5be3ad 100644 --- a/app/home/management/commands/populate_homepage.py +++ b/app/home/management/commands/populate_homepage.py @@ -37,6 +37,9 @@ def handle(self, *args, **options): available_images = Image.objects.all() selected_image = None image_embed = "" + hero_image = None + hero_text = None + hero_cta = None if available_images.exists(): # Select a random image @@ -47,6 +50,10 @@ def handle(self, *args, **options): f'format="left" id="{selected_image.id}"/>' ) self.stdout.write(f"Selected image: {selected_image.title}") + # Set hero section fields if they are not already set + hero_image = selected_image + hero_text = "Your Hero Section Title" + hero_cta = "Your Hero Section CTA, you need to set a link" else: self.stdout.write( "No images found - content will be created without images" @@ -100,6 +107,12 @@ def handle(self, *args, **options):

Happy building with Wagtail!

""".strip() + if hero_image: + # Update the hero section fields + home_page.image = hero_image + home_page.hero_text = hero_text + home_page.hero_cta = hero_cta + # Update the home page body content home_page.body = sample_content home_page.save() From 158ccbf10870a7fc1e04b41ee42c59f68d7f3d53 Mon Sep 17 00:00:00 2001 From: nickmoreton Date: Fri, 15 Aug 2025 16:07:56 +0100 Subject: [PATCH 18/20] Remove conflicting template tags --- app/home/templatetags/__init__.py | 0 app/home/templatetags/navigation_tags.py | 10 ---------- 2 files changed, 10 deletions(-) delete mode 100644 app/home/templatetags/__init__.py delete mode 100644 app/home/templatetags/navigation_tags.py diff --git a/app/home/templatetags/__init__.py b/app/home/templatetags/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/app/home/templatetags/navigation_tags.py b/app/home/templatetags/navigation_tags.py deleted file mode 100644 index c6e6309..0000000 --- a/app/home/templatetags/navigation_tags.py +++ /dev/null @@ -1,10 +0,0 @@ -from django import template - -from app.blog.models import BlogIndexPage - -register = template.Library() - - -@register.simple_tag -def get_blog_index_url(): - return BlogIndexPage.objects.first().url From de7091f0cbbc01cf51fa642051ef2e05c3494308 Mon Sep 17 00:00:00 2001 From: nickmoreton Date: Fri, 15 Aug 2025 16:24:54 +0100 Subject: [PATCH 19/20] Update failing test --- app/home/tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/home/tests.py b/app/home/tests.py index c681f59..bacc9bf 100644 --- a/app/home/tests.py +++ b/app/home/tests.py @@ -35,7 +35,6 @@ def test_home_frontend_returns_200(self): """Test that the home page frontend returns 200 OK.""" response = self.client.get("/") self.assertEqual(response.status_code, 200) - self.assertContains(response, "Wagtail Blog Tutorial") self.assertTemplateUsed(response, "home/home_page.html") def test_home_admin_edit_returns_200(self): From 1b719cce38acc8d67f214c76a15969d5162a1416 Mon Sep 17 00:00:00 2001 From: Nick Moreton Date: Sun, 28 Dec 2025 21:36:02 +0000 Subject: [PATCH 20/20] Alter order of class Meta --- app/base/models.py | 7 +++---- app/portfolio/blocks.py | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/base/models.py b/app/base/models.py index e2b0a75..1540386 100644 --- a/app/base/models.py +++ b/app/base/models.py @@ -46,7 +46,6 @@ class FooterText( TranslatableMixin, models.Model, ): - body = RichTextField() panels = [ @@ -54,6 +53,9 @@ class FooterText( PublishingPanel(), ] + class Meta(TranslatableMixin.Meta): + verbose_name_plural = "Footer Text" + def __str__(self): return "Footer text" @@ -63,9 +65,6 @@ def get_preview_template(self, request, mode_name): def get_preview_context(self, request, mode_name): return {"footer_text": self.body} - class Meta(TranslatableMixin.Meta): - verbose_name_plural = "Footer Text" - class FormField(AbstractFormField): page = ParentalKey("FormPage", on_delete=models.CASCADE, related_name="form_fields") diff --git a/app/portfolio/blocks.py b/app/portfolio/blocks.py index 11fd69f..44a1ade 100644 --- a/app/portfolio/blocks.py +++ b/app/portfolio/blocks.py @@ -31,6 +31,5 @@ class Meta: class PortfolioStreamBlock(BaseStreamBlock): - card = CardBlock(group="Sections") featured_posts = FeaturedPostsBlock(group="Sections")