From 10cc2c840a12f0404fa4c99a30c140e968188d43 Mon Sep 17 00:00:00 2001 From: Sylvain Boissel Date: Mon, 25 Mar 2024 18:10:52 +0100 Subject: [PATCH] Add authors list and category colophon at the end of pages --- blog/locale/fr/LC_MESSAGES/django.po | 70 +++++++++++------ .../0006_author_blogentrypage_authors.py | 41 ++++++++++ ...ory_colophon_alter_author_role_and_more.py | 38 +++++++++ blog/models.py | 41 +++++++++- blog/templates/blog/blog_entry_page.html | 78 ++++++++++++++----- blog/templates/blog/blog_index_page.html | 1 + static/css/style.css | 10 +++ static/css/style.sass | 10 +++ 8 files changed, 244 insertions(+), 45 deletions(-) create mode 100644 blog/migrations/0006_author_blogentrypage_authors.py create mode 100644 blog/migrations/0007_category_colophon_alter_author_role_and_more.py diff --git a/blog/locale/fr/LC_MESSAGES/django.po b/blog/locale/fr/LC_MESSAGES/django.po index cad128f6..89aabec8 100644 --- a/blog/locale/fr/LC_MESSAGES/django.po +++ b/blog/locale/fr/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-03-11 16:15+0100\n" -"PO-Revision-Date: 2024-02-27 11:32+0100\n" +"POT-Creation-Date: 2024-03-25 17:57+0100\n" +"PO-Revision-Date: 2024-03-25 17:58+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: fr\n" @@ -18,83 +18,107 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Poedit 3.4\n" -#: blog/models.py:34 +#: blog/models.py:35 msgid "Posts per page" msgstr "Articles par page" -#: blog/models.py:44 +#: blog/models.py:45 msgid "Blog index" msgstr "Index de blog" -#: blog/models.py:72 blog/templates/blog/tags_list_page.html:20 +#: blog/models.py:73 blog/templates/blog/tags_list_page.html:20 #: blog/views.py:149 msgid "Tags" msgstr "Étiquettes" -#: blog/models.py:95 blog/models.py:167 blog/models.py:248 +#: blog/models.py:96 blog/models.py:169 blog/models.py:264 #: blog/templates/blog/categories_list_page.html:20 blog/views.py:117 msgid "Categories" msgstr "Catégories" -#: blog/models.py:107 blog/templates/blog/blog_index_page.html:58 +#: blog/models.py:108 blog/templates/blog/blog_index_page.html:59 msgid "Posts written by" msgstr "Articles écrits par" -#: blog/models.py:169 +#: blog/models.py:171 msgid "Post date" msgstr "Date de publication" -#: blog/models.py:175 -msgid "Author" -msgstr "Auteur" - -#: blog/models.py:187 +#: blog/models.py:190 msgid "Scheduled publishing" msgstr "Publication planifiée" -#: blog/models.py:195 +#: blog/models.py:198 msgid "Tags and Categories" msgstr "Étiquettes et Catégories" -#: blog/models.py:203 +#: blog/models.py:206 msgid "Blog page" msgstr "Page de blog" -#: blog/models.py:208 +#: blog/models.py:211 msgid "Category name" msgstr "Nom de la catégorie" -#: blog/models.py:215 +#: blog/models.py:218 msgid "Parent category" msgstr "Catégorie parente" -#: blog/models.py:218 +#: blog/models.py:224 msgid "Description" msgstr "Description" -#: blog/models.py:229 +#: blog/models.py:225 +msgid "Displayed on the top of the category page" +msgstr "Affiché en haut de la page de la catégorie" + +#: blog/models.py:230 +msgid "Colophon" +msgstr "Colophon" + +#: blog/models.py:231 +msgid "Text displayed at the end of every page in the category" +msgstr "Texte affiché à la fin de chaque page de la catégorie" + +#: blog/models.py:244 msgid "Parent category cannot be self." msgstr "La catégorie ne peut être sa propre parente." -#: blog/models.py:231 +#: blog/models.py:246 msgid "Cannot have circular Parents." msgstr "Il est impossible d’avoir des parents circulaires." -#: blog/models.py:247 blog/models.py:259 +#: blog/models.py:263 blog/models.py:275 msgid "Category" msgstr "Catégorie" +#: blog/models.py:289 +msgid "Name" +msgstr "Nom" + +#: blog/models.py:290 +msgid "Role" +msgstr "Fonction" + +#: blog/models.py:305 +msgid "Author" +msgstr "Auteur" + +#: blog/templates/blog/blog_entry_page.html:78 +msgid "Posted by:" +msgstr "Écrit par :" + #: blog/templates/blog/blog_index_page.html:52 #, python-format msgid "Posts in category %(category)s" msgstr "Articles dans la catégorie %(category)s" -#: blog/templates/blog/blog_index_page.html:55 +#: blog/templates/blog/blog_index_page.html:56 #, python-format msgid "Posts tagged with %(tag)s" msgstr "Articles avec l’étiquette %(tag)s" -#: blog/templates/blog/blog_index_page.html:60 +#: blog/templates/blog/blog_index_page.html:61 #, python-format msgid "Posts published in %(year)s" msgstr "Articles publiés en %(year)s" diff --git a/blog/migrations/0006_author_blogentrypage_authors.py b/blog/migrations/0006_author_blogentrypage_authors.py new file mode 100644 index 00000000..954d6392 --- /dev/null +++ b/blog/migrations/0006_author_blogentrypage_authors.py @@ -0,0 +1,41 @@ +# Generated by Django 5.0.3 on 2024-03-21 13:54 + +import django.db.models.deletion +import modelcluster.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("blog", "0005_delete_tag_blogentrypage_header_cta_text_and_more"), + ("wagtailimages", "0025_alter_image_file_alter_rendition_file"), + ] + + operations = [ + migrations.CreateModel( + name="Author", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("name", models.CharField(max_length=255, verbose_name="Name")), + ("role", models.CharField(max_length=255, verbose_name="Function")), + ( + "author_image", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="wagtailimages.image", + ), + ), + ], + options={ + "verbose_name": "Author", + }, + ), + migrations.AddField( + model_name="blogentrypage", + name="authors", + field=modelcluster.fields.ParentalManyToManyField(blank=True, to="blog.author"), + ), + ] diff --git a/blog/migrations/0007_category_colophon_alter_author_role_and_more.py b/blog/migrations/0007_category_colophon_alter_author_role_and_more.py new file mode 100644 index 00000000..aa9a7bb9 --- /dev/null +++ b/blog/migrations/0007_category_colophon_alter_author_role_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 5.0.3 on 2024-03-25 16:48 + +import wagtail.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("blog", "0006_author_blogentrypage_authors"), + ] + + operations = [ + migrations.AddField( + model_name="category", + name="colophon", + field=wagtail.fields.RichTextField( + blank=True, + help_text="Text displayed at the end of every page in the category", + max_length=500, + verbose_name="Colophon", + ), + ), + migrations.AlterField( + model_name="author", + name="role", + field=models.CharField(max_length=255, verbose_name="Role"), + ), + migrations.AlterField( + model_name="category", + name="description", + field=models.CharField( + blank=True, + help_text="Displayed on the top of the category page", + max_length=500, + verbose_name="Description", + ), + ), + ] diff --git a/blog/models.py b/blog/models.py index 17c93fb7..8f2d6e44 100644 --- a/blog/models.py +++ b/blog/models.py @@ -15,6 +15,7 @@ from taggit.models import TaggedItemBase from wagtail.admin.panels import FieldPanel, FieldRowPanel, MultiFieldPanel, TitleFieldPanel from wagtail.admin.widgets.slug import SlugInput +from wagtail.fields import RichTextField from wagtail.models.i18n import Locale, TranslatableMixin from wagtail.search import index from wagtail.snippets.models import register_snippet @@ -126,6 +127,7 @@ def get_context(self, request, tag=None, category=None, author=None, year=None, context["posts"] = posts if category is not None: context["category"] = category.name + context["category_description"] = category.description context["tag"] = tag context["author"] = author context["year"] = year @@ -167,12 +169,13 @@ class BlogEntryPage(SitesFacilesBasePage): verbose_name=_("Categories"), ) date = models.DateTimeField(verbose_name=_("Post date"), default=timezone.now) + authors = ParentalManyToManyField("blog.Author", blank=True) parent_page_types = ["blog.BlogIndexPage"] subpage_types = [] settings_panels = SitesFacilesBasePage.settings_panels + [ - FieldPanel("owner", heading=_("Author")), + FieldPanel("authors"), FieldPanel("date"), MultiFieldPanel( [ @@ -215,7 +218,19 @@ class Category(TranslatableMixin, index.Indexed, models.Model): verbose_name=_("Parent category"), on_delete=models.SET_NULL, ) - description = models.CharField(max_length=500, blank=True, verbose_name=_("Description")) + description = models.CharField( + max_length=500, + blank=True, + verbose_name=_("Description"), + help_text=_("Displayed on the top of the category page"), + ) + colophon = RichTextField( + max_length=500, + blank=True, + verbose_name=_("Colophon"), + help_text=_("Text displayed at the end of every page in the category"), + features=["h2", "h3", "bold", "italic", "link"], + ) objects = CategoryManager() @@ -239,6 +254,7 @@ def save(self, *args, **kwargs): TitleFieldPanel("name"), FieldPanel("slug", widget=SlugInput), FieldPanel("description"), + FieldPanel("colophon"), FieldPanel("parent"), ] @@ -266,3 +282,24 @@ def __str__(self): class TagEntryPage(TaggedItemBase): content_object = ParentalKey("BlogEntryPage", related_name="entry_tags") + + +@register_snippet +class Author(models.Model): + name = models.CharField(_("Name"), max_length=255) + role = models.CharField(_("Role"), max_length=255) + author_image = models.ForeignKey( + "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+" + ) + + panels = [ + FieldPanel("name"), + FieldPanel("role"), + FieldPanel("author_image"), + ] + + def __str__(self): + return self.name + + class Meta: + verbose_name = _("Author") diff --git a/blog/templates/blog/blog_entry_page.html b/blog/templates/blog/blog_entry_page.html index 00db2de1..9e58358b 100644 --- a/blog/templates/blog/blog_entry_page.html +++ b/blog/templates/blog/blog_entry_page.html @@ -1,6 +1,6 @@ {% extends "base.html" %} -{% load static dsfr_tags wagtailcore_tags wagtailimages_tags %} +{% load static dsfr_tags wagtailcore_tags wagtailimages_tags i18n %} {% block title %} {{ page.seo_title|default:page.title }} — {{ settings.content_manager.CmsDsfrConfig.site_title }} @@ -46,29 +46,67 @@ {% include "content_manager/blocks/heading.html" %} {% include "content_manager/blocks/messages.html" %} -
-
-
- {% include "content_manager/blocks/breadcrumbs.html" %} -

{{ page.title }}

+ {% with categories=page.blog_categories.all %} + +
+
+
+ {% include "content_manager/blocks/breadcrumbs.html" %} +

{{ page.title }}

+
+

+ Publié le {{ page.date |date:'l j F Y' }} + {% if categories %} + | + {% for category in categories %} + {{ category.name }} + {% if not forloop.last %},{% endif %} + {% endfor %} + {% endif %} +

-

- Publié le {{ page.date |date:'l j F Y' }} - {% if page.owner.first_name and page.owner.last_name %} - par {{ page.owner.first_name }} {{ page.owner.last_name }} - {% endif %} - {% if page.blog_categories.all %} - | - {% for category in page.blog_categories.all %} - {{ category.name }} - {% if not forloop.last %},{% endif %} - {% endfor %} + + {% include "content_manager/blocks/blocks_stream.html" %} + + {% with authors=page.authors.all %} + {% if authors %} +

+

{% translate "Posted by:" %}

+
+ {% for author in authors %} + {% image author.author_image fill-200x200 as author_image %} +
+
+
+
+

{{ author.name }}

+

{{ author.role }}

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

-
+ {% endwith %} - {% include "content_manager/blocks/blocks_stream.html" %} + {% if categories %} +
+ {% for category in categories %}

{{ category.colophon|richtext }}

{% endfor %} +
+ {% endif %} + {% endwith %}
{% for tag in page.tags.all|dictsort:"slug" %} diff --git a/blog/templates/blog/blog_index_page.html b/blog/templates/blog/blog_index_page.html index 36c98b64..fb097320 100644 --- a/blog/templates/blog/blog_index_page.html +++ b/blog/templates/blog/blog_index_page.html @@ -50,6 +50,7 @@ {% if category %} {% dsfr_breadcrumb breadcrumb %}

{% blocktranslate %}Posts in category {{ category }}{% endblocktranslate %}

+ {% if category_description %}

{{ category_description }}

{% endif %} {% elif tag %} {% dsfr_breadcrumb breadcrumb %}

{% blocktranslate %}Posts tagged with {{ tag }}{% endblocktranslate %}

diff --git a/static/css/style.css b/static/css/style.css index ddc445bb..711dc7c3 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -15,3 +15,13 @@ .fr-header__service-title em { font-weight: lighter; } + +.cmsfr-author_card__header { + flex: 0 0 6rem !important; + width: 6rem !important; } + +.cmsfr-author-img { + border-radius: 50%; + height: 4.5rem !important; + margin: 1.5rem; + width: 4.5rem; } diff --git a/static/css/style.sass b/static/css/style.sass index c17516a6..d48a5da0 100644 --- a/static/css/style.sass +++ b/static/css/style.sass @@ -17,3 +17,13 @@ .fr-header__service-title em font-weight: lighter + +.cmsfr-author_card__header + flex: 0 0 6rem !important + width: 6rem !important + +.cmsfr-author-img + border-radius: 50% + height: 4.5rem !important + margin: 1.5rem + width: 4.5rem