diff --git a/.gitignore b/.gitignore
index 310dba0..e6e39b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -187,3 +187,6 @@ static/
# mkdocs
/site
+
+# Media files
+/media
diff --git a/cms/jinja2/templates/pages/information_page.html b/cms/jinja2/templates/pages/information_page.html
new file mode 100644
index 0000000..28608ad
--- /dev/null
+++ b/cms/jinja2/templates/pages/information_page.html
@@ -0,0 +1,27 @@
+{% extends "templates/base_page.html" %}
+{% from "components/related-content/_macro.njk" import onsRelatedContent %}
+
+{% block main %}
+
{{ page.summary }}
+
+{% if page.last_updated %}
+ Last Updated: {{ page.last_updated }}
+{% endif %}
+
+{% include_block page.content %}
+
+{% if related_pages %}
+ {# fmt:off #}
+ {{-
+ onsRelatedContent({
+ "ariaLabel": _('Related content'),
+ "rows": [{
+ "id": 'related-content',
+ "title": _('Related content'),
+ "itemsList": related_pages
+ }]
+ })
+ -}}
+ {# fmt:on #}
+{% endif %}
+
diff --git a/cms/settings/base.py b/cms/settings/base.py
index 9511f86..b9619af 100644
--- a/cms/settings/base.py
+++ b/cms/settings/base.py
@@ -63,6 +63,7 @@
"cms.themes",
"cms.topics",
"cms.users",
+ "cms.standard_pages",
"wagtail.embeds",
"wagtail.sites",
"wagtail.users",
diff --git a/cms/standard_pages/__init__.py b/cms/standard_pages/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/cms/standard_pages/apps.py b/cms/standard_pages/apps.py
new file mode 100644
index 0000000..c0ccd0b
--- /dev/null
+++ b/cms/standard_pages/apps.py
@@ -0,0 +1,8 @@
+from django.apps import AppConfig
+
+
+class StandardPagesConfig(AppConfig):
+ """The standard_pages app config."""
+
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "cms.standard_pages"
diff --git a/cms/standard_pages/migrations/0001_initial.py b/cms/standard_pages/migrations/0001_initial.py
new file mode 100644
index 0000000..4c4559d
--- /dev/null
+++ b/cms/standard_pages/migrations/0001_initial.py
@@ -0,0 +1,64 @@
+# Generated by Django 5.1.2 on 2024-11-08 15:48
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+import cms.core.fields
+
+
+class Migration(migrations.Migration):
+ initial = True
+
+ dependencies = [
+ ("images", "0001_initial"),
+ ("wagtailcore", "0094_alter_page_locale"),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="InformationPage",
+ 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",
+ ),
+ ),
+ ("listing_title", models.CharField(blank=True, max_length=255)),
+ ("listing_summary", models.CharField(blank=True, max_length=255)),
+ ("social_text", models.CharField(blank=True, max_length=255)),
+ ("summary", models.TextField(max_length=255)),
+ ("last_updated", models.DateField(blank=True, null=True)),
+ ("content", cms.core.fields.StreamField(block_lookup={})),
+ (
+ "listing_image",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.customimage",
+ ),
+ ),
+ (
+ "social_image",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to="images.customimage",
+ ),
+ ),
+ ],
+ options={
+ "abstract": False,
+ },
+ bases=("wagtailcore.page", models.Model),
+ ),
+ ]
diff --git a/cms/standard_pages/migrations/__init__.py b/cms/standard_pages/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/cms/standard_pages/models.py b/cms/standard_pages/models.py
new file mode 100644
index 0000000..499be4d
--- /dev/null
+++ b/cms/standard_pages/models.py
@@ -0,0 +1,39 @@
+from typing import ClassVar
+
+from django.db import models
+from wagtail.admin.panels import FieldPanel
+from wagtail.search import index
+
+from cms.core.blocks.stream_blocks import CoreStoryBlock
+from cms.core.fields import StreamField
+from cms.core.models import BasePage
+
+
+class InformationPage(BasePage): # type: ignore[django-manager-missing]
+ """A generic information page model."""
+
+ template = "templates/pages/information_page.html"
+
+ parent_page_types: ClassVar[list[str]] = [
+ # Ensures that the information page can only be created under the home page
+ "home.HomePage",
+ # Ensures that the information page can be created under another information page
+ "standard_pages.InformationPage",
+ ]
+
+ summary = models.TextField(max_length=255)
+ last_updated = models.DateField(blank=True, null=True)
+ content = StreamField(CoreStoryBlock())
+
+ content_panels: ClassVar[list[FieldPanel]] = [
+ *BasePage.content_panels,
+ FieldPanel("summary"),
+ FieldPanel("last_updated"),
+ FieldPanel("content"),
+ ]
+
+ search_fields: ClassVar[list[index.SearchField | index.AutocompleteField]] = [
+ *BasePage.search_fields,
+ index.SearchField("summary"),
+ index.SearchField("content"),
+ ]
diff --git a/cms/static_src/sass/main.scss b/cms/static_src/sass/main.scss
index 25dbf2f..e82d9fe 100644
--- a/cms/static_src/sass/main.scss
+++ b/cms/static_src/sass/main.scss
@@ -2,3 +2,19 @@
body {
display: block;
}
+
+// Custom CSS from Wagtail doc to enable responsive video embeds
+.responsive-object {
+ position: relative;
+}
+
+.responsive-object iframe,
+.responsive-object object,
+.responsive-object embed {
+ position: absolute;
+ top: 0;
+ /* stylelint-disable-next-line property-disallowed-list */
+ left: 0;
+ width: 100%;
+ height: 100%;
+}