diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 00000000..05c5cbd7 --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,31 @@ +name: 📦 Docker Image Build & Push + +on: + push: + branches: + - "**" + +jobs: + docker: + runs-on: ubuntu-latest + name: Build and push Docker image + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Inject enhanced GitHub environment variables + uses: rlespinasse/github-slug-action@v5 + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} + - name: Build and push + uses: docker/build-push-action@v6 + with: + push: true + tags: | + ghcr.io/${{ env.GITHUB_REPOSITORY_OWNER_PART_SLUG }}/sites-faciles:${{ env.GITHUB_REF_SLUG }} + ${{ github.ref_name == 'main' && format('ghcr.io/{0}/sites-faciles:latest', env.GITHUB_REPOSITORY_OWNER_PART_SLUG) || '' }} + cache-from: type=registry,ref=ghcr.io/${{ env.GITHUB_REPOSITORY_OWNER_PART_SLUG }}/sites-faciles:${{ env.GITHUB_REF_SLUG }} + cache-to: type=inline diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a81131be..1ce3fbe6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,11 +2,11 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.9 + rev: v0.8.0 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] - repo: https://github.com/psf/black - rev: 23.11.0 + rev: 24.10.0 hooks: - id: black diff --git a/Dockerfile b/Dockerfile index d36ecc35..d96a6644 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.10 -EXPOSE ${HOST_PORT} +EXPOSE ${CONTAINER_PORT} ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 @@ -13,10 +13,13 @@ ENV POETRY_HOME=/opt/poetry ENV POETRY_VENV=/opt/poetry-venv ENV POETRY_CACHE_DIR=/opt/.cache +# Needed for docker build to succeed +ENV DATABASE_URL=postgres://user:password@localhost:5432/db + # Add new user to run the whole thing as non-root. RUN set -ex \ - && addgroup app \ - && adduser --ingroup app --home ${APP_DIR} --disabled-password app; + && addgroup --gid 1000 app \ + && adduser --uid 1000 --gid 1000 --home ${APP_DIR} --disabled-password app; # Install poetry separated from system interpreter RUN python3 -m venv ${POETRY_VENV} \ @@ -40,4 +43,4 @@ USER app ENTRYPOINT ["./entrypoint.sh"] # https://stackoverflow.com/a/40454758/21676629 -CMD ["sh", "-c", "poetry run python manage.py runserver 0.0.0.0:$HOST_PORT"] +CMD ["sh", "-c", "poetry run python manage.py runserver 0.0.0.0:$CONTAINER_PORT"] diff --git a/blog/locale/fr/LC_MESSAGES/django.mo b/blog/locale/fr/LC_MESSAGES/django.mo index 9efe6853..c7000ea4 100644 Binary files a/blog/locale/fr/LC_MESSAGES/django.mo and b/blog/locale/fr/LC_MESSAGES/django.mo differ diff --git a/blog/locale/fr/LC_MESSAGES/django.po b/blog/locale/fr/LC_MESSAGES/django.po index 18255ea5..13d7b4ee 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-09-17 12:04+0200\n" -"PO-Revision-Date: 2024-09-17 12:04+0200\n" +"POT-Creation-Date: 2024-11-27 14:45+0100\n" +"PO-Revision-Date: 2024-11-27 14:47+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: fr\n" @@ -18,19 +18,19 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Poedit 3.4.2\n" -#: blog/blocks.py:9 blog/models.py:37 blog/models.py:65 +#: blog/blocks.py:9 blog/models.py:39 blog/models.py:67 msgid "Name" msgstr "Nom" -#: blog/blocks.py:10 blog/models.py:66 +#: blog/blocks.py:10 blog/models.py:68 msgid "Role" msgstr "Fonction" -#: blog/blocks.py:11 blog/models.py:54 +#: blog/blocks.py:11 blog/models.py:56 msgid "Organization" msgstr "Organisation" -#: blog/blocks.py:12 blog/models.py:68 +#: blog/blocks.py:12 blog/models.py:70 msgid "Contact info" msgstr "Informations de contact" @@ -42,120 +42,124 @@ msgstr "Texte riche" msgid "Contact card" msgstr "Carte contact" -#: blog/models.py:93 +#: blog/models.py:95 msgid "Person" msgstr "Personne" -#: blog/models.py:105 +#: blog/models.py:107 msgid "Category name" msgstr "Nom de la catégorie" -#: blog/models.py:112 +#: blog/models.py:114 msgid "Parent category" msgstr "Catégorie parente" -#: blog/models.py:119 +#: blog/models.py:121 msgid "Description" msgstr "Description" -#: blog/models.py:120 +#: blog/models.py:122 msgid "Displayed on the top of the category page" msgstr "Affiché en haut de la page de la catégorie" -#: blog/models.py:126 +#: blog/models.py:128 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:153 +#: blog/models.py:155 msgid "Parent category cannot be self." msgstr "La catégorie ne peut être sa propre parente." -#: blog/models.py:155 +#: blog/models.py:157 msgid "Cannot have circular Parents." msgstr "Il est impossible d’avoir des parents circulaires." -#: blog/models.py:164 blog/models.py:183 +#: blog/models.py:166 blog/models.py:185 msgid "Category" msgstr "Catégorie" -#: blog/models.py:165 blog/models.py:273 blog/models.py:390 -#: blog/templates/blog/categories_list_page.html:20 blog/views.py:117 +#: blog/models.py:167 blog/models.py:279 blog/models.py:460 blog/models.py:467 +#: blog/models.py:518 msgid "Categories" msgstr "Catégories" -#: blog/models.py:199 +#: blog/models.py:201 msgid "Posts per page" msgstr "Articles par page" -#: blog/models.py:203 blog/templates/blog/blog_index_page.html:77 +#: blog/models.py:207 +msgid "Post limit in the RSS/Atom feeds" +msgstr "Nombre d’articles dans les flux RSS/Atom" + +#: blog/models.py:211 blog/templates/blog/blog_index_page.html:85 msgid "Filter by category" msgstr "Filtrer par catégorie" -#: blog/models.py:204 blog/templates/blog/blog_index_page.html:94 +#: blog/models.py:212 blog/templates/blog/blog_index_page.html:102 msgid "Filter by tag" msgstr "Filtrer par étiquette" -#: blog/models.py:205 blog/templates/blog/blog_index_page.html:111 +#: blog/models.py:213 blog/templates/blog/blog_index_page.html:119 msgid "Filter by author" msgstr "Filtrer par auteur" -#: blog/models.py:207 blog/templates/blog/blog_index_page.html:126 +#: blog/models.py:215 blog/templates/blog/blog_index_page.html:134 msgid "Filter by source" msgstr "Filtrer par source" -#: blog/models.py:207 +#: blog/models.py:215 msgid "The source is the organization of the post author" msgstr "La source est l’organisation à laquelle appartient l’auteur de l’article" -#: blog/models.py:219 +#: blog/models.py:228 msgid "Show filters" msgstr "Afficher les filtres" -#: blog/models.py:226 +#: blog/models.py:235 msgid "Blog index" msgstr "Index de blog" -#: blog/models.py:255 blog/templates/blog/tags_list_page.html:20 -#: blog/views.py:149 +#: blog/models.py:262 blog/models.py:483 blog/models.py:497 +#: blog/templates/blog/tags_list_page.html:20 msgid "Tags" msgstr "Étiquettes" -#: blog/models.py:260 +#: blog/models.py:267 #, python-format msgid "Posts tagged with %(tag)s" msgstr "Articles avec l’étiquette %(tag)s" -#: blog/models.py:278 +#: blog/models.py:284 #, python-format msgid "Posts in category %(category)s" msgstr "Articles dans la catégorie %(category)s" -#: blog/models.py:289 blog/models.py:291 blog/models.py:302 blog/models.py:305 +#: blog/models.py:294 blog/models.py:296 blog/models.py:306 blog/models.py:309 msgid "Posts written by" msgstr "Articles écrits par" -#: blog/models.py:309 +#: blog/models.py:314 #, python-format msgid "Posts published in %(year)s" msgstr "Articles publiés en %(year)s" -#: blog/models.py:392 +#: blog/models.py:520 msgid "Post date" msgstr "Date de publication" -#: blog/models.py:394 +#: blog/models.py:522 msgid "Author entries can be created in Snippets > Persons" msgstr "Les auteurs peuvent être créés via Fragments > Personnes" -#: blog/models.py:413 +#: blog/models.py:541 msgid "Scheduled publishing" msgstr "Publication planifiée" -#: blog/models.py:421 +#: blog/models.py:549 msgid "Tags and Categories" msgstr "Étiquettes et Catégories" -#: blog/models.py:437 +#: blog/models.py:565 msgid "Blog page" msgstr "Page de blog" @@ -163,12 +167,28 @@ msgstr "Page de blog" msgid "No article found." msgstr "Aucun article trouvé." -#: blog/templates/blog/blog_entry_page.html:74 +#: blog/templates/blog/blocks/feeds.html:10 +msgid "Atom feed for the category" +msgstr "Flux Atom pour la catégorie" + +#: blog/templates/blog/blocks/feeds.html:12 +msgid "Atom feed" +msgstr "Flux Atom" + +#: blog/templates/blog/blocks/feeds.html:20 +msgid "RSS feed for the category" +msgstr "Flux RSS pour la catégorie" + +#: blog/templates/blog/blocks/feeds.html:22 +msgid "RSS feed" +msgstr "Flux RSS" + +#: blog/templates/blog/blog_entry_page.html:79 msgid "Posted by:" msgstr "Écrit par :" -#: blog/templates/blog/blog_index_page.html:72 -#: blog/templates/blog/blog_index_page.html:74 +#: blog/templates/blog/blog_index_page.html:80 +#: blog/templates/blog/blog_index_page.html:82 msgid "Filters" msgstr "Filtres" diff --git a/blog/migrations/0038_blogindexpage_feed_posts_limit.py b/blog/migrations/0038_blogindexpage_feed_posts_limit.py new file mode 100644 index 00000000..caf285e5 --- /dev/null +++ b/blog/migrations/0038_blogindexpage_feed_posts_limit.py @@ -0,0 +1,25 @@ +# Generated by Django 5.1.3 on 2024-11-27 10:47 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("blog", "0037_alter_blogentrypage_body_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="blogindexpage", + name="feed_posts_limit", + field=models.PositiveSmallIntegerField( + default=20, + validators=[ + django.core.validators.MaxValueValidator(100), + django.core.validators.MinValueValidator(1), + ], + verbose_name="Post limit in the RSS/Atom feeds", + ), + ), + ] diff --git a/blog/migrations/0039_alter_blogentrypage_body_alter_blogindexpage_body_and_more.py b/blog/migrations/0039_alter_blogentrypage_body_alter_blogindexpage_body_and_more.py new file mode 100644 index 00000000..b0bcb20b --- /dev/null +++ b/blog/migrations/0039_alter_blogentrypage_body_alter_blogindexpage_body_and_more.py @@ -0,0 +1,3844 @@ +# Generated by Django 5.1.3 on 2024-12-05 14:24 + +import wagtail.fields +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("blog", "0038_blogindexpage_feed_posts_limit"), + ] + + operations = [ + migrations.AlterField( + model_name="blogentrypage", + name="body", + field=wagtail.fields.StreamField( + [ + ("paragraph", 0), + ("image", 9), + ("imageandtext", 22), + ("alert", 27), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("video", 53), + ("transcription", 54), + ("badges_list", 59), + ("tags_list", 64), + ("link", 65), + ("stepper", 71), + ("card", 93), + ("tile", 103), + ("tabs", 137), + ("markdown", 138), + ("iframe", 139), + ("separator", 142), + ("multicolumns", 151), + ("item_grid", 154), + ("fullwidthbackground", 156), + ("fullwidthbackgroundwithsidemenu", 163), + ("subpageslist", 164), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("html", 165), + ], + blank=True, + block_lookup={ + 0: ("wagtail.blocks.RichTextBlock", (), {"label": "Rich text"}), + 1: ("wagtail.blocks.CharBlock", (), {"label": "Title", "required": False}), + 2: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ("h5", "Heading 5"), + ("h6", "Heading 6"), + ("p", "Paragraph"), + ], + "help_text": "Adapt to the page layout. Defaults to heading 3.", + "label": "Heading level", + "required": False, + }, + ), + 3: ("wagtail.images.blocks.ImageChooserBlock", (), {"label": "Image"}), + 4: ( + "wagtail.blocks.CharBlock", + (), + {"label": "Alternative text (textual description of the image)", "required": False}, + ), + 5: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("fr-content-media--sm", "Small"), + ("", "Medium"), + ("fr-content-media--lg", "Large"), + ], + "label": "Witdh", + "required": False, + }, + ), + 6: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("fr-ratio-32x9", "32x9"), + ("fr-ratio-16x9", "16x9"), + ("fr-ratio-3x2", "3x2"), + ("fr-ratio-4x3", "4x3"), + ("fr-ratio-1x1", "1x1"), + ("fr-ratio-3x4", "3x4"), + ("fr-ratio-2x3", "2x3"), + ], + "label": "Image ratio", + "required": False, + }, + ), + 7: ("wagtail.blocks.CharBlock", (), {"label": "Caption", "required": False}), + 8: ("wagtail.blocks.URLBlock", (), {"label": "Link", "required": False}), + 9: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 1), + ("heading_tag", 2), + ("image", 3), + ("alt", 4), + ("width", 5), + ("image_ratio", 6), + ("caption", 7), + ("url", 8), + ] + ], + {}, + ), + 10: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("left", "Left"), ("right", "Right")], + "label": "Side where the image is displayed", + }, + ), + 11: ( + "wagtail.blocks.ChoiceBlock", + [], + {"choices": [("3", "3/12"), ("5", "5/12"), ("6", "6/12")], "label": "Image width"}, + ), + 12: ( + "wagtail.blocks.PageChooserBlock", + (), + { + "help_text": "Link to a page of this site. Use either this, the document, or the external URL parameter.", + "label": "Page", + "required": False, + }, + ), + 13: ( + "wagtail.documents.blocks.DocumentChooserBlock", + (), + { + "help_text": "Use either this, the external URL or the page parameter.", + "label": "Document", + "required": False, + }, + ), + 14: ( + "wagtail.blocks.URLBlock", + (), + { + "help_text": "Use either this, the document or the page parameter.", + "label": "External URL", + "required": False, + }, + ), + 15: ("wagtail.blocks.CharBlock", (), {"label": "Link label", "required": False}), + 16: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("", "No icon"), + ("fr-icon-arrow-right-line fr-link--icon-right", "Icon on the right side"), + ("fr-icon-arrow-right-line fr-link--icon-left", "Icon on the left side"), + ], + "help_text": "Only used for internal links.", + "label": "Icon", + "required": False, + }, + ), + 17: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-link--sm", "Small"), ("", "Medium"), ("fr-link--lg", "Large")], + "label": "Size", + "required": False, + }, + ), + 18: ( + "wagtail.blocks.StructBlock", + [ + [ + ("page", 12), + ("document", 13), + ("external_url", 14), + ("text", 15), + ("icon", 16), + ("size", 17), + ] + ], + { + "help_text": "The link is shown at the bottom of the text block, with an arrow", + "label": "Link", + "required": False, + }, + ), + 19: ( + "wagtail.blocks.CharBlock", + (), + { + "group": "obsolete", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "Link label (obsolete)", + "required": False, + }, + ), + 20: ( + "wagtail.blocks.PageChooserBlock", + (), + { + "group": "obsolete", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "Internal link (obsolete)", + "required": False, + }, + ), + 21: ( + "wagtail.blocks.URLBlock", + (), + { + "group": "obsolete", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "Link URL (obsolete)", + "required": False, + }, + ), + 22: ( + "wagtail.blocks.StructBlock", + [ + [ + ("image", 3), + ("image_side", 10), + ("image_ratio", 11), + ("text", 0), + ("link", 18), + ("link_label", 19), + ("page", 20), + ("link_url", 21), + ] + ], + {"label": "Image and text"}, + ), + 23: ("wagtail.blocks.CharBlock", (), {"label": "Message title", "required": False}), + 24: ("wagtail.blocks.TextBlock", (), {"label": "Message text", "required": False}), + 25: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("error", "Error"), + ("success", "Success"), + ("info", "Information"), + ("warning", "Warning"), + ], + "label": "Message type", + }, + ), + 26: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ("h5", "Heading 5"), + ("h6", "Heading 6"), + ("p", "Paragraph"), + ], + "help_text": "Adapt to the page layout. Defaults to heading 3.", + "label": "Heading level", + }, + ), + 27: ( + "wagtail.blocks.StructBlock", + [[("title", 23), ("description", 24), ("level", 25), ("heading_tag", 26)]], + {"label": "Alert message"}, + ), + 28: ("wagtail.blocks.CharBlock", (), {"label": "Title"}), + 29: ("wagtail.blocks.RichTextBlock", (), {"label": "Content"}), + 30: ( + "wagtail.blocks.StructBlock", + [[("title", 28), ("content", 29)]], + {"label": "Accordion", "max_num": 15, "min_num": 1}, + ), + 31: ( + "wagtail.blocks.StreamBlock", + [[("title", 28), ("accordion", 30)]], + {"group": "DSFR components", "label": "Accordions"}, + ), + 32: ("content_manager.blocks.IconPickerBlock", (), {"label": "Icon", "required": False}), + 33: ( + "wagtail.blocks.RichTextBlock", + (), + { + "features": [ + "bold", + "italic", + "link", + "document-link", + "superscript", + "subscript", + "strikethrough", + ], + "label": "Content", + "required": False, + }, + ), + 34: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("fr-btn", "Primary"), + ("fr-btn fr-btn--secondary", "Secundary"), + ("fr-btn fr-btn--tertiary", "Tertiary"), + ("fr-btn fr-btn--tertiary-no-outline", "Tertiary without border"), + ], + "label": "Button type", + "required": False, + }, + ), + 35: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-btn--icon-left", "Left"), ("fr-btn--icon-right", "Right")], + "label": "Icon side", + "required": False, + }, + ), + 36: ( + "wagtail.blocks.StructBlock", + [ + [ + ("page", 12), + ("document", 13), + ("external_url", 14), + ("text", 15), + ("button_type", 34), + ("icon_class", 32), + ("icon_side", 35), + ] + ], + {"label": "Button", "required": False}, + ), + 37: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("green-tilleul-verveine", "Tilleul verveine"), + ("green-bourgeon", "Bourgeon"), + ("green-emeraude", "Émeraude"), + ("green-menthe", "Menthe"), + ("green-archipel", "Archipel"), + ("blue-ecume", "Écume"), + ("blue-cumulus", "Cumulus"), + ("purple-glycine", "Glycine"), + ("pink-macaron", "Macaron"), + ("pink-tuile", "Tuile"), + ("yellow-tournesol", "Tournesol"), + ("yellow-moutarde", "Moutarde"), + ("orange-terre-battue", "Terre battue"), + ("brown-cafe-creme", "Café crème"), + ("brown-caramel", "Caramel"), + ("brown-opera", "Opéra"), + ("beige-gris-galet", "Gris galet"), + ], + "label": "Color", + "required": False, + }, + ), + 38: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 1), + ("heading_tag", 26), + ("icon_class", 32), + ("text", 33), + ("button", 36), + ("color", 37), + ] + ], + {"group": "DSFR components", "label": "Callout"}, + ), + 39: ( + "wagtail.blocks.RichTextBlock", + (), + { + "features": [ + "bold", + "italic", + "link", + "document-link", + "superscript", + "subscript", + "strikethrough", + ], + "label": "Content", + }, + ), + 40: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-text--sm", "Small"), ("", "Medium"), ("fr-text--lg", "Large")], + "label": "Size", + "required": False, + }, + ), + 41: ( + "wagtail.blocks.StructBlock", + [[("text", 39), ("color", 37), ("size", 40)]], + {"group": "DSFR components", "label": "Highlight"}, + ), + 42: ("wagtail.images.blocks.ImageChooserBlock", (), {"label": "Image", "required": False}), + 43: ("wagtail.blocks.CharBlock", (), {"label": "Quote"}), + 44: ("wagtail.blocks.CharBlock", (), {"label": "Author name", "required": False}), + 45: ("wagtail.blocks.CharBlock", (), {"label": "Author title", "required": False}), + 46: ( + "wagtail.blocks.StructBlock", + [[("image", 42), ("quote", 43), ("author_name", 44), ("author_title", 45), ("color", 37)]], + {"group": "DSFR components", "label": "Quote"}, + ), + 47: ("wagtail.blocks.CharBlock", (), {"label": "Video title", "required": False}), + 48: ( + "wagtail.blocks.URLBlock", + (), + { + "help_text": "Use embed format, with a version that doesn't require a consent banner if available. (e.g. : https://www.youtube-nocookie.com/embed/gLzXOViPX-0) For Youtube, use Embed video and check Enable privacy-enhanced mode.", + "label": "Video URL", + }, + ), + 49: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-ratio-16x9", "16x9"), ("fr-ratio-4x3", "4x3"), ("fr-ratio-1x1", "1x1")], + "label": "Video ratio", + "required": False, + }, + ), + 50: ( + "wagtail.blocks.CharBlock", + (), + {"default": "Transcription", "label": "Title", "required": False}, + ), + 51: ("wagtail.blocks.RichTextBlock", (), {"label": "Transcription content", "required": False}), + 52: ( + "wagtail.blocks.StructBlock", + [[("title", 50), ("content", 51)]], + {"label": "Transcription", "required": False}, + ), + 53: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 47), + ("caption", 7), + ("url", 48), + ("width", 5), + ("video_ratio", 49), + ("transcription", 52), + ] + ], + {"label": "Video"}, + ), + 54: ("wagtail.blocks.StructBlock", [[("title", 50), ("content", 51)]], {"label": "Transcription"}), + 55: ("wagtail.blocks.CharBlock", (), {"label": "Badge label", "required": False}), + 56: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("", [("new", "New"), ("grey", "Grey")]), + ( + "System colors", + [ + ("info", "Info"), + ("success", "Success"), + ("warning", "Warning"), + ("error", "Error"), + ], + ), + ( + "Illustration colors", + [ + ("green-tilleul-verveine", "Tilleul verveine"), + ("green-bourgeon", "Bourgeon"), + ("green-emeraude", "Émeraude"), + ("green-menthe", "Menthe"), + ("green-archipel", "Archipel"), + ("blue-ecume", "Écume"), + ("blue-cumulus", "Cumulus"), + ("purple-glycine", "Glycine"), + ("pink-macaron", "Macaron"), + ("pink-tuile", "Tuile"), + ("yellow-tournesol", "Tournesol"), + ("yellow-moutarde", "Moutarde"), + ("orange-terre-battue", "Terre battue"), + ("brown-cafe-creme", "Café crème"), + ("brown-caramel", "Caramel"), + ("brown-opera", "Opéra"), + ("beige-gris-galet", "Gris galet"), + ], + ), + ], + "label": "Badge color", + "required": False, + }, + ), + 57: ("wagtail.blocks.BooleanBlock", (), {"label": "Hide badge icon", "required": False}), + 58: ( + "wagtail.blocks.StructBlock", + [[("text", 55), ("color", 56), ("hide_icon", 57)]], + {"label": "Badge"}, + ), + 59: ("wagtail.blocks.StreamBlock", [[("badge", 58)]], {"label": "Badge list"}), + 60: ("wagtail.blocks.BooleanBlock", (), {"label": "Small tag", "required": False}), + 61: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("green-tilleul-verveine", "Tilleul verveine"), + ("green-bourgeon", "Bourgeon"), + ("green-emeraude", "Émeraude"), + ("green-menthe", "Menthe"), + ("green-archipel", "Archipel"), + ("blue-ecume", "Écume"), + ("blue-cumulus", "Cumulus"), + ("purple-glycine", "Glycine"), + ("pink-macaron", "Macaron"), + ("pink-tuile", "Tuile"), + ("yellow-tournesol", "Tournesol"), + ("yellow-moutarde", "Moutarde"), + ("orange-terre-battue", "Terre battue"), + ("brown-cafe-creme", "Café crème"), + ("brown-caramel", "Caramel"), + ("brown-opera", "Opéra"), + ("beige-gris-galet", "Gris galet"), + ], + "help_text": "Only for clickable tags", + "label": "Tag color", + "required": False, + }, + ), + 62: ( + "wagtail.blocks.StructBlock", + [[("page", 12), ("document", 13), ("external_url", 14)]], + {"required": False}, + ), + 63: ( + "wagtail.blocks.StructBlock", + [[("label", 28), ("is_small", 60), ("color", 61), ("icon_class", 32), ("link", 62)]], + {"label": "Tag"}, + ), + 64: ("wagtail.blocks.StreamBlock", [[("tag", 63)]], {"label": "Tag list"}), + 65: ( + "wagtail.blocks.StructBlock", + [ + [ + ("page", 12), + ("document", 13), + ("external_url", 14), + ("text", 15), + ("icon", 16), + ("size", 17), + ] + ], + {"label": "Single link"}, + ), + 66: ( + "wagtail.blocks.IntegerBlock", + (), + {"label": "Number of steps", "max_value": 8, "min_value": 1}, + ), + 67: ("wagtail.blocks.IntegerBlock", (), {"label": "Current step", "max_value": 8, "min_value": 1}), + 68: ("wagtail.blocks.TextBlock", (), {"label": "Detail"}), + 69: ("wagtail.blocks.StructBlock", [[("title", 28), ("detail", 68)]], {"label": "Step"}), + 70: ("wagtail.blocks.StreamBlock", [[("step", 69)]], {"label": "Steps"}), + 71: ( + "wagtail.blocks.StructBlock", + [[("title", 28), ("total", 66), ("current", 67), ("steps", 70)]], + {"group": "DSFR components", "label": "Stepper"}, + ), + 72: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-card--horizontal-tier", "1/3"), ("fr-card--horizontal-half", "50/50")], + "label": "Image ratio", + "required": False, + }, + ), + 73: ( + "wagtail.blocks.StreamBlock", + [[("badge", 58)]], + { + "help_text": "Only used if the card has an image.", + "label": "Image area badge", + "max_num": 1, + "required": False, + }, + ), + 74: ( + "wagtail.blocks.StructBlock", + [[("page", 12), ("document", 13), ("external_url", 14)]], + {"label": "Link", "required": False}, + ), + 75: ( + "wagtail.blocks.URLBlock", + (), + { + "group": "target", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "Link (obsolete)", + "required": False, + }, + ), + 76: ( + "wagtail.documents.blocks.DocumentChooserBlock", + (), + { + "group": "target", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "or Document (obsolete)", + "required": False, + }, + ), + 77: ("wagtail.blocks.CharBlock", (), {"label": "Top detail: text", "required": False}), + 78: ( + "content_manager.blocks.IconPickerBlock", + (), + {"label": "Top detail: icon", "required": False}, + ), + 79: ("wagtail.blocks.StreamBlock", [[("badge", 58)]], {}), + 80: ("wagtail.blocks.StreamBlock", [[("tag", 63)]], {}), + 81: ( + "wagtail.blocks.StreamBlock", + [[("badges", 79), ("tags", 80)]], + {"label": "Top detail: badges or tags", "max_num": 1, "required": False}, + ), + 82: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "Incompatible with the bottom call-to-action. If the card links to a downloadable document, the values are pre-filled.", + "label": "Bottom detail: text", + "required": False, + }, + ), + 83: ( + "content_manager.blocks.IconPickerBlock", + (), + {"label": "Bottom detail: icon", "required": False}, + ), + 84: ( + "wagtail.blocks.StructBlock", + [[("page", 12), ("document", 13), ("external_url", 14), ("text", 15)]], + {"label": "Link"}, + ), + 85: ("wagtail.blocks.StreamBlock", [[("link", 84)]], {}), + 86: ( + "wagtail.blocks.StructBlock", + [ + [ + ("page", 12), + ("document", 13), + ("external_url", 14), + ("text", 15), + ("button_type", 34), + ("icon_class", 32), + ("icon_side", 35), + ] + ], + {"label": "Button"}, + ), + 87: ( + "wagtail.blocks.StreamBlock", + [[("button", 86)]], + { + "help_text": "Please use only one primary button.\n If you use icons, use them on all buttons and align them on the same side.", + "label": "Buttons", + }, + ), + 88: ( + "wagtail.blocks.StreamBlock", + [[("links", 85), ("buttons", 87)]], + { + "help_text": "Incompatible with the bottom detail text.", + "label": "Bottom call-to-action: links or buttons", + "max_num": 1, + "required": False, + }, + ), + 89: ("wagtail.blocks.BooleanBlock", (), {"label": "Card with grey background", "required": False}), + 90: ("wagtail.blocks.BooleanBlock", (), {"label": "Card without background", "required": False}), + 91: ("wagtail.blocks.BooleanBlock", (), {"label": "Card without border", "required": False}), + 92: ("wagtail.blocks.BooleanBlock", (), {"label": "Card with a shadow", "required": False}), + 93: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 28), + ("heading_tag", 26), + ("description", 33), + ("image", 42), + ("image_ratio", 72), + ("image_badge", 73), + ("link", 74), + ("url", 75), + ("document", 76), + ("top_detail_text", 77), + ("top_detail_icon", 78), + ("top_detail_badges_tags", 81), + ("bottom_detail_text", 82), + ("bottom_detail_icon", 83), + ("call_to_action", 88), + ("grey_background", 89), + ("no_background", 90), + ("no_border", 91), + ("shadow", 92), + ] + ], + {"group": "DSFR components", "label": "Horizontal card"}, + ), + 94: ( + "wagtail.blocks.RichTextBlock", + (), + { + "features": ["bold", "italic", "superscript", "subscript", "strikethrough"], + "label": "Content", + "required": False, + }, + ), + 95: ( + "wagtail.images.blocks.ImageChooserBlock", + (), + {"help_text": "Prefer SVG files.", "label": "Image", "required": False}, + ), + 96: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "If the tile links to a downloadable document, the values are pre-filled.", + "label": "Detail text", + "required": False, + }, + ), + 97: ("wagtail.blocks.BooleanBlock", (), {"label": "Small tile", "required": False}), + 98: ("wagtail.blocks.BooleanBlock", (), {"label": "Tile with grey background", "required": False}), + 99: ("wagtail.blocks.BooleanBlock", (), {"label": "Tile without background", "required": False}), + 100: ("wagtail.blocks.BooleanBlock", (), {"label": "Tile without border", "required": False}), + 101: ("wagtail.blocks.BooleanBlock", (), {"label": "Tile with a shadow", "required": False}), + 102: ("wagtail.blocks.BooleanBlock", (), {"label": "Horizontal tile", "required": False}), + 103: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 28), + ("heading_tag", 26), + ("description", 94), + ("image", 95), + ("link", 74), + ("top_detail_badges_tags", 81), + ("detail_text", 96), + ("is_small", 97), + ("grey_background", 98), + ("no_background", 99), + ("no_border", 100), + ("shadow", 101), + ("is_horizontal", 102), + ] + ], + {"group": "DSFR components", "label": "Tile"}, + ), + 104: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 1), + ("heading_tag", 2), + ("image", 3), + ("alt", 4), + ("width", 5), + ("image_ratio", 6), + ("caption", 7), + ("url", 8), + ] + ], + {"label": "Image"}, + ), + 105: ("wagtail.blocks.RichTextBlock", (), {"label": "Rich text", "required": False}), + 106: ( + "wagtail.blocks.StreamBlock", + [[("buttons", 87)]], + {"label": "Call-to-action buttons", "max_num": 1, "required": False}, + ), + 107: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the CTA buttons above.", + "label": "Call to action label (obsolete)", + "required": False, + }, + ), + 108: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the CTA buttons above.", + "label": "Link (obsolete)", + "required": False, + }, + ), + 109: ( + "wagtail.blocks.StructBlock", + [[("text", 105), ("cta_buttons", 106), ("cta_label", 107), ("cta_url", 108)]], + {"label": "Text and call to action"}, + ), + 110: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "Accessibility: The title should describe, in a clear and concise manner, the embedded content.", + "label": "Title", + }, + ), + 111: ( + "wagtail.blocks.URLBlock", + (), + { + "help_text": "Example for Tally: https://tally.so/embed/w2jMRa", + "label": "URL of the iframe", + }, + ), + 112: ("wagtail.blocks.IntegerBlock", (), {"label": "Height (in pixels)"}), + 113: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "For example: \"allow='geolocation'\".", + "label": "Parameters", + "required": False, + }, + ), + 114: ( + "wagtail.blocks.StructBlock", + [[("title", 110), ("url", 111), ("height", 112), ("parameters", 113)]], + {"group": "DSFR components", "label": "Iframe"}, + ), + 115: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ("h5", "Heading 5"), + ], + "help_text": "Adapt to the page layout. Defaults to heading 2.", + "label": "Heading level", + "required": False, + }, + ), + 116: ( + "wagtail.blocks.PageChooserBlock", + (), + {"label": "Blog", "page_type": ["blog.BlogIndexPage"]}, + ), + 117: ( + "wagtail.blocks.IntegerBlock", + (), + { + "default": 3, + "label": "Number of entries", + "max_value": 8, + "min_value": 1, + "required": False, + }, + ), + 118: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("blog.Category",), + {"label": "Filter by category", "required": False}, + ), + 119: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("content_manager.Tag",), + {"label": "Filter by tag", "required": False}, + ), + 120: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("blog.Person",), + {"label": "Filter by author", "required": False}, + ), + 121: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("blog.Organization",), + { + "help_text": "The source is the organization of the post author", + "label": "Filter by source", + "required": False, + }, + ), + 122: ( + "wagtail.blocks.BooleanBlock", + (), + {"default": False, "label": "Show filters", "required": False}, + ), + 123: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 1), + ("heading_tag", 115), + ("blog", 116), + ("entries_count", 117), + ("category_filter", 118), + ("tag_filter", 119), + ("author_filter", 120), + ("source_filter", 121), + ("show_filters", 122), + ] + ], + {"group": "Website structure", "label": "Blog recent entries"}, + ), + 124: ( + "wagtail.blocks.PageChooserBlock", + (), + {"label": "Event calendar", "page_type": ["events.EventsIndexPage"]}, + ), + 125: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 1), + ("heading_tag", 115), + ("index_page", 124), + ("entries_count", 117), + ("category_filter", 118), + ("tag_filter", 119), + ("author_filter", 120), + ("source_filter", 121), + ("show_filters", 122), + ] + ], + {"group": "Website structure", "label": "Event calendar recent entries"}, + ), + 126: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "Incompatible with the bottom call-to-action.", + "label": "Bottom detail: text", + "required": False, + }, + ), + 127: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 28), + ("heading_tag", 26), + ("description", 33), + ("image", 42), + ("image_ratio", 6), + ("image_badge", 73), + ("link", 74), + ("url", 75), + ("document", 76), + ("top_detail_text", 77), + ("top_detail_icon", 78), + ("top_detail_badges_tags", 81), + ("bottom_detail_text", 126), + ("bottom_detail_icon", 83), + ("call_to_action", 88), + ("grey_background", 89), + ("no_background", 90), + ("no_border", 91), + ("shadow", 92), + ] + ], + {"group": "DSFR components", "label": "Vertical card"}, + ), + 128: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("blog.Person",), + { + "help_text": "Optional, all values can be manually specified or overriden below", + "label": "Person", + "required": False, + }, + ), + 129: ("wagtail.blocks.CharBlock", (), {"label": "Name", "max_length": 255, "required": False}), + 130: ("wagtail.blocks.CharBlock", (), {"label": "Role", "max_length": 255, "required": False}), + 131: ( + "wagtail.blocks.CharBlock", + (), + {"label": "Organization", "max_length": 255, "required": False}, + ), + 132: ( + "wagtail.blocks.CharBlock", + (), + {"label": "Contact info", "max_length": 500, "required": False}, + ), + 133: ("wagtail.blocks.StreamBlock", [[("tag", 63)]], {"label": "Tags", "required": False}), + 134: ( + "wagtail.blocks.StructBlock", + [ + [ + ("contact", 128), + ("link", 74), + ("heading_tag", 2), + ("name", 129), + ("role", 130), + ("organization", 131), + ("contact_info", 132), + ("image", 42), + ("tags", 133), + ] + ], + {"group": "Extra components", "label": "Contact card"}, + ), + 135: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 104), + ("video", 53), + ("transcription", 54), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("stepper", 71), + ("text_cta", 109), + ("link", 65), + ("iframe", 114), + ("tile", 103), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("card", 127), + ("contact_card", 134), + ] + ], + {"label": "Content"}, + ), + 136: ( + "wagtail.blocks.StructBlock", + [[("title", 28), ("content", 135)]], + {"label": "Tab", "max_num": 15, "min_num": 1}, + ), + 137: ( + "wagtail.blocks.StreamBlock", + [[("tabs", 136)]], + {"group": "DSFR components", "label": "Tabs"}, + ), + 138: ("wagtailmarkdown.blocks.MarkdownBlock", (), {"group": "Expert syntax", "label": "Markdown"}), + 139: ( + "wagtail.blocks.StructBlock", + [[("title", 110), ("url", 111), ("height", 112), ("parameters", 113)]], + {"group": "Expert syntax", "label": "Iframe"}, + ), + 140: ( + "wagtail.blocks.IntegerBlock", + (), + {"default": 3, "label": "Top margin", "max_value": 15, "min_value": 0}, + ), + 141: ( + "wagtail.blocks.IntegerBlock", + (), + {"default": 3, "label": "Bottom margin", "max_value": 15, "min_value": 0}, + ), + 142: ( + "wagtail.blocks.StructBlock", + [[("top_margin", 140), ("bottom_margin", 141)]], + {"group": "Page structure", "label": "Separator"}, + ), + 143: ( + "wagtail.images.blocks.ImageChooserBlock", + (), + {"label": "Background image", "required": False}, + ), + 144: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("Primary colors", [("blue-france", "Blue France"), ("red-marianne", "Red Marianne")]), + ("Neutral colors", [("grey", "Grey")]), + ( + "Illustration colors", + [ + ("green-tilleul-verveine", "Tilleul verveine"), + ("green-bourgeon", "Bourgeon"), + ("green-emeraude", "Émeraude"), + ("green-menthe", "Menthe"), + ("green-archipel", "Archipel"), + ("blue-ecume", "Écume"), + ("blue-cumulus", "Cumulus"), + ("purple-glycine", "Glycine"), + ("pink-macaron", "Macaron"), + ("pink-tuile", "Tuile"), + ("yellow-tournesol", "Tournesol"), + ("yellow-moutarde", "Moutarde"), + ("orange-terre-battue", "Terre battue"), + ("brown-cafe-creme", "Café crème"), + ("brown-caramel", "Caramel"), + ("brown-opera", "Opéra"), + ("beige-gris-galet", "Gris galet"), + ], + ), + ], + "help_text": "Uses the French Design System colors", + "label": "Background color", + "required": False, + }, + ), + 145: ( + "wagtail.blocks.RegexBlock", + (), + { + "error_messages": {"invalid": "Incorrect color format, must be #fff or #f5f5f5"}, + "help_text": "This field is obsolete and will be removed in the near future. Replace it with the background color.", + "label": "Background color, hexadecimal format (obsolete)", + "regex": "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$", + "required": False, + }, + ), + 146: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ("h5", "Heading 5"), + ("h6", "Heading 6"), + ("p", "Paragraph"), + ], + "help_text": "Adapt to the page layout. Defaults to heading 2.", + "label": "Heading level", + "required": False, + }, + ), + 147: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("3", "3/12"), + ("4", "4/12"), + ("5", "5/12"), + ("6", "6/12"), + ("7", "7/12"), + ("8", "8/12"), + ("9", "9/12"), + ], + "help_text": "The total width of all columns should be 12.", + "label": "Column width", + "required": False, + }, + ), + 148: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 104), + ("video", 53), + ("transcription", 54), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("stepper", 71), + ("text_cta", 109), + ("link", 65), + ("iframe", 114), + ("tile", 103), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("card", 127), + ("contact_card", 134), + ] + ], + {"label": "Column content"}, + ), + 149: ( + "wagtail.blocks.StructBlock", + [[("width", 147), ("content", 148)]], + {"group": "Page structure", "label": "Adjustable column"}, + ), + 150: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 104), + ("video", 53), + ("transcription", 54), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("stepper", 71), + ("text_cta", 109), + ("link", 65), + ("iframe", 114), + ("tile", 103), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("card", 127), + ("column", 149), + ] + ], + {"label": "Columns"}, + ), + 151: ( + "wagtail.blocks.StructBlock", + [ + [ + ("bg_image", 143), + ("bg_color_class", 144), + ("bg_color", 145), + ("title", 1), + ("heading_tag", 146), + ("columns", 150), + ] + ], + {"group": "Page structure", "label": "Multiple columns"}, + ), + 152: ( + "wagtail.blocks.ChoiceBlock", + [], + {"choices": [("3", "3/12"), ("4", "4/12"), ("6", "6/12")], "label": "Column width"}, + ), + 153: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 104), + ("video", 53), + ("transcription", 54), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("stepper", 71), + ("text_cta", 109), + ("link", 65), + ("iframe", 114), + ("tile", 103), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("card", 127), + ("contact_card", 134), + ] + ], + {"label": "Items"}, + ), + 154: ( + "wagtail.blocks.StructBlock", + [[("column_width", 152), ("items", 153)]], + {"group": "Page structure", "label": "Item grid"}, + ), + 155: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 104), + ("video", 53), + ("transcription", 54), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("stepper", 71), + ("text_cta", 109), + ("link", 65), + ("iframe", 114), + ("tile", 103), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("image_and_text", 22), + ("card", 93), + ("tabs", 137), + ("item_grid", 154), + ] + ], + {"label": "Content"}, + ), + 156: ( + "wagtail.blocks.StructBlock", + [[("bg_image", 143), ("bg_color_class", 144), ("content", 155)]], + {"group": "Page structure", "label": "Full width background"}, + ), + 157: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 104), + ("video", 53), + ("transcription", 54), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("stepper", 71), + ("text_cta", 109), + ("link", 65), + ("iframe", 114), + ("tile", 103), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("image_and_text", 22), + ("card", 93), + ("tabs", 137), + ("item_grid", 154), + ] + ], + {"label": "Main content"}, + ), + 158: ("wagtail.blocks.CharBlock", (), {"label": "Side menu title", "required": False}), + 159: ( + "wagtail.blocks.RawHTMLBlock", + (), + { + "help_text": "Warning: Use HTML block with caution. Malicious code can compromise the security of the site.", + "label": "HTML", + }, + ), + 160: ("wagtail.blocks.PageChooserBlock", (), {"label": "Parent page"}), + 161: ("wagtail.blocks.StructBlock", [[("page", 160)]], {"label": "Page tree"}), + 162: ( + "wagtail.blocks.StreamBlock", + [[("html", 159), ("pagetree", 161)]], + {"label": "Side menu content"}, + ), + 163: ( + "wagtail.blocks.StructBlock", + [ + [ + ("bg_image", 143), + ("bg_color_class", 144), + ("main_content", 157), + ("sidemenu_title", 158), + ("sidemenu_content", 162), + ] + ], + {"group": "Page structure", "label": "Full width background with side menu"}, + ), + 164: ( + "wagtail.blocks.static_block.StaticBlock", + (), + { + "admin_text": "A simple, alphabetical list of the subpages of the current page.", + "group": "Website structure", + "label": "Subpages list", + "template": "content_manager/blocks/subpages_list.html", + }, + ), + 165: ( + "wagtail.blocks.RawHTMLBlock", + (), + { + "group": "Expert syntax", + "help_text": "Warning: Use HTML block with caution. Malicious code can compromise the security of the site.", + "readonly": True, + }, + ), + }, + ), + ), + migrations.AlterField( + model_name="blogindexpage", + name="body", + field=wagtail.fields.StreamField( + [ + ("paragraph", 0), + ("image", 9), + ("imageandtext", 22), + ("alert", 27), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("video", 53), + ("transcription", 54), + ("badges_list", 59), + ("tags_list", 64), + ("link", 65), + ("stepper", 71), + ("card", 93), + ("tile", 103), + ("tabs", 137), + ("markdown", 138), + ("iframe", 139), + ("separator", 142), + ("multicolumns", 151), + ("item_grid", 154), + ("fullwidthbackground", 156), + ("fullwidthbackgroundwithsidemenu", 163), + ("subpageslist", 164), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("html", 165), + ], + blank=True, + block_lookup={ + 0: ("wagtail.blocks.RichTextBlock", (), {"label": "Rich text"}), + 1: ("wagtail.blocks.CharBlock", (), {"label": "Title", "required": False}), + 2: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ("h5", "Heading 5"), + ("h6", "Heading 6"), + ("p", "Paragraph"), + ], + "help_text": "Adapt to the page layout. Defaults to heading 3.", + "label": "Heading level", + "required": False, + }, + ), + 3: ("wagtail.images.blocks.ImageChooserBlock", (), {"label": "Image"}), + 4: ( + "wagtail.blocks.CharBlock", + (), + {"label": "Alternative text (textual description of the image)", "required": False}, + ), + 5: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("fr-content-media--sm", "Small"), + ("", "Medium"), + ("fr-content-media--lg", "Large"), + ], + "label": "Witdh", + "required": False, + }, + ), + 6: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("fr-ratio-32x9", "32x9"), + ("fr-ratio-16x9", "16x9"), + ("fr-ratio-3x2", "3x2"), + ("fr-ratio-4x3", "4x3"), + ("fr-ratio-1x1", "1x1"), + ("fr-ratio-3x4", "3x4"), + ("fr-ratio-2x3", "2x3"), + ], + "label": "Image ratio", + "required": False, + }, + ), + 7: ("wagtail.blocks.CharBlock", (), {"label": "Caption", "required": False}), + 8: ("wagtail.blocks.URLBlock", (), {"label": "Link", "required": False}), + 9: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 1), + ("heading_tag", 2), + ("image", 3), + ("alt", 4), + ("width", 5), + ("image_ratio", 6), + ("caption", 7), + ("url", 8), + ] + ], + {}, + ), + 10: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("left", "Left"), ("right", "Right")], + "label": "Side where the image is displayed", + }, + ), + 11: ( + "wagtail.blocks.ChoiceBlock", + [], + {"choices": [("3", "3/12"), ("5", "5/12"), ("6", "6/12")], "label": "Image width"}, + ), + 12: ( + "wagtail.blocks.PageChooserBlock", + (), + { + "help_text": "Link to a page of this site. Use either this, the document, or the external URL parameter.", + "label": "Page", + "required": False, + }, + ), + 13: ( + "wagtail.documents.blocks.DocumentChooserBlock", + (), + { + "help_text": "Use either this, the external URL or the page parameter.", + "label": "Document", + "required": False, + }, + ), + 14: ( + "wagtail.blocks.URLBlock", + (), + { + "help_text": "Use either this, the document or the page parameter.", + "label": "External URL", + "required": False, + }, + ), + 15: ("wagtail.blocks.CharBlock", (), {"label": "Link label", "required": False}), + 16: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("", "No icon"), + ("fr-icon-arrow-right-line fr-link--icon-right", "Icon on the right side"), + ("fr-icon-arrow-right-line fr-link--icon-left", "Icon on the left side"), + ], + "help_text": "Only used for internal links.", + "label": "Icon", + "required": False, + }, + ), + 17: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-link--sm", "Small"), ("", "Medium"), ("fr-link--lg", "Large")], + "label": "Size", + "required": False, + }, + ), + 18: ( + "wagtail.blocks.StructBlock", + [ + [ + ("page", 12), + ("document", 13), + ("external_url", 14), + ("text", 15), + ("icon", 16), + ("size", 17), + ] + ], + { + "help_text": "The link is shown at the bottom of the text block, with an arrow", + "label": "Link", + "required": False, + }, + ), + 19: ( + "wagtail.blocks.CharBlock", + (), + { + "group": "obsolete", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "Link label (obsolete)", + "required": False, + }, + ), + 20: ( + "wagtail.blocks.PageChooserBlock", + (), + { + "group": "obsolete", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "Internal link (obsolete)", + "required": False, + }, + ), + 21: ( + "wagtail.blocks.URLBlock", + (), + { + "group": "obsolete", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "Link URL (obsolete)", + "required": False, + }, + ), + 22: ( + "wagtail.blocks.StructBlock", + [ + [ + ("image", 3), + ("image_side", 10), + ("image_ratio", 11), + ("text", 0), + ("link", 18), + ("link_label", 19), + ("page", 20), + ("link_url", 21), + ] + ], + {"label": "Image and text"}, + ), + 23: ("wagtail.blocks.CharBlock", (), {"label": "Message title", "required": False}), + 24: ("wagtail.blocks.TextBlock", (), {"label": "Message text", "required": False}), + 25: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("error", "Error"), + ("success", "Success"), + ("info", "Information"), + ("warning", "Warning"), + ], + "label": "Message type", + }, + ), + 26: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ("h5", "Heading 5"), + ("h6", "Heading 6"), + ("p", "Paragraph"), + ], + "help_text": "Adapt to the page layout. Defaults to heading 3.", + "label": "Heading level", + }, + ), + 27: ( + "wagtail.blocks.StructBlock", + [[("title", 23), ("description", 24), ("level", 25), ("heading_tag", 26)]], + {"label": "Alert message"}, + ), + 28: ("wagtail.blocks.CharBlock", (), {"label": "Title"}), + 29: ("wagtail.blocks.RichTextBlock", (), {"label": "Content"}), + 30: ( + "wagtail.blocks.StructBlock", + [[("title", 28), ("content", 29)]], + {"label": "Accordion", "max_num": 15, "min_num": 1}, + ), + 31: ( + "wagtail.blocks.StreamBlock", + [[("title", 28), ("accordion", 30)]], + {"group": "DSFR components", "label": "Accordions"}, + ), + 32: ("content_manager.blocks.IconPickerBlock", (), {"label": "Icon", "required": False}), + 33: ( + "wagtail.blocks.RichTextBlock", + (), + { + "features": [ + "bold", + "italic", + "link", + "document-link", + "superscript", + "subscript", + "strikethrough", + ], + "label": "Content", + "required": False, + }, + ), + 34: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("fr-btn", "Primary"), + ("fr-btn fr-btn--secondary", "Secundary"), + ("fr-btn fr-btn--tertiary", "Tertiary"), + ("fr-btn fr-btn--tertiary-no-outline", "Tertiary without border"), + ], + "label": "Button type", + "required": False, + }, + ), + 35: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-btn--icon-left", "Left"), ("fr-btn--icon-right", "Right")], + "label": "Icon side", + "required": False, + }, + ), + 36: ( + "wagtail.blocks.StructBlock", + [ + [ + ("page", 12), + ("document", 13), + ("external_url", 14), + ("text", 15), + ("button_type", 34), + ("icon_class", 32), + ("icon_side", 35), + ] + ], + {"label": "Button", "required": False}, + ), + 37: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("green-tilleul-verveine", "Tilleul verveine"), + ("green-bourgeon", "Bourgeon"), + ("green-emeraude", "Émeraude"), + ("green-menthe", "Menthe"), + ("green-archipel", "Archipel"), + ("blue-ecume", "Écume"), + ("blue-cumulus", "Cumulus"), + ("purple-glycine", "Glycine"), + ("pink-macaron", "Macaron"), + ("pink-tuile", "Tuile"), + ("yellow-tournesol", "Tournesol"), + ("yellow-moutarde", "Moutarde"), + ("orange-terre-battue", "Terre battue"), + ("brown-cafe-creme", "Café crème"), + ("brown-caramel", "Caramel"), + ("brown-opera", "Opéra"), + ("beige-gris-galet", "Gris galet"), + ], + "label": "Color", + "required": False, + }, + ), + 38: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 1), + ("heading_tag", 26), + ("icon_class", 32), + ("text", 33), + ("button", 36), + ("color", 37), + ] + ], + {"group": "DSFR components", "label": "Callout"}, + ), + 39: ( + "wagtail.blocks.RichTextBlock", + (), + { + "features": [ + "bold", + "italic", + "link", + "document-link", + "superscript", + "subscript", + "strikethrough", + ], + "label": "Content", + }, + ), + 40: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-text--sm", "Small"), ("", "Medium"), ("fr-text--lg", "Large")], + "label": "Size", + "required": False, + }, + ), + 41: ( + "wagtail.blocks.StructBlock", + [[("text", 39), ("color", 37), ("size", 40)]], + {"group": "DSFR components", "label": "Highlight"}, + ), + 42: ("wagtail.images.blocks.ImageChooserBlock", (), {"label": "Image", "required": False}), + 43: ("wagtail.blocks.CharBlock", (), {"label": "Quote"}), + 44: ("wagtail.blocks.CharBlock", (), {"label": "Author name", "required": False}), + 45: ("wagtail.blocks.CharBlock", (), {"label": "Author title", "required": False}), + 46: ( + "wagtail.blocks.StructBlock", + [[("image", 42), ("quote", 43), ("author_name", 44), ("author_title", 45), ("color", 37)]], + {"group": "DSFR components", "label": "Quote"}, + ), + 47: ("wagtail.blocks.CharBlock", (), {"label": "Video title", "required": False}), + 48: ( + "wagtail.blocks.URLBlock", + (), + { + "help_text": "Use embed format, with a version that doesn't require a consent banner if available. (e.g. : https://www.youtube-nocookie.com/embed/gLzXOViPX-0) For Youtube, use Embed video and check Enable privacy-enhanced mode.", + "label": "Video URL", + }, + ), + 49: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-ratio-16x9", "16x9"), ("fr-ratio-4x3", "4x3"), ("fr-ratio-1x1", "1x1")], + "label": "Video ratio", + "required": False, + }, + ), + 50: ( + "wagtail.blocks.CharBlock", + (), + {"default": "Transcription", "label": "Title", "required": False}, + ), + 51: ("wagtail.blocks.RichTextBlock", (), {"label": "Transcription content", "required": False}), + 52: ( + "wagtail.blocks.StructBlock", + [[("title", 50), ("content", 51)]], + {"label": "Transcription", "required": False}, + ), + 53: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 47), + ("caption", 7), + ("url", 48), + ("width", 5), + ("video_ratio", 49), + ("transcription", 52), + ] + ], + {"label": "Video"}, + ), + 54: ("wagtail.blocks.StructBlock", [[("title", 50), ("content", 51)]], {"label": "Transcription"}), + 55: ("wagtail.blocks.CharBlock", (), {"label": "Badge label", "required": False}), + 56: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("", [("new", "New"), ("grey", "Grey")]), + ( + "System colors", + [ + ("info", "Info"), + ("success", "Success"), + ("warning", "Warning"), + ("error", "Error"), + ], + ), + ( + "Illustration colors", + [ + ("green-tilleul-verveine", "Tilleul verveine"), + ("green-bourgeon", "Bourgeon"), + ("green-emeraude", "Émeraude"), + ("green-menthe", "Menthe"), + ("green-archipel", "Archipel"), + ("blue-ecume", "Écume"), + ("blue-cumulus", "Cumulus"), + ("purple-glycine", "Glycine"), + ("pink-macaron", "Macaron"), + ("pink-tuile", "Tuile"), + ("yellow-tournesol", "Tournesol"), + ("yellow-moutarde", "Moutarde"), + ("orange-terre-battue", "Terre battue"), + ("brown-cafe-creme", "Café crème"), + ("brown-caramel", "Caramel"), + ("brown-opera", "Opéra"), + ("beige-gris-galet", "Gris galet"), + ], + ), + ], + "label": "Badge color", + "required": False, + }, + ), + 57: ("wagtail.blocks.BooleanBlock", (), {"label": "Hide badge icon", "required": False}), + 58: ( + "wagtail.blocks.StructBlock", + [[("text", 55), ("color", 56), ("hide_icon", 57)]], + {"label": "Badge"}, + ), + 59: ("wagtail.blocks.StreamBlock", [[("badge", 58)]], {"label": "Badge list"}), + 60: ("wagtail.blocks.BooleanBlock", (), {"label": "Small tag", "required": False}), + 61: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("green-tilleul-verveine", "Tilleul verveine"), + ("green-bourgeon", "Bourgeon"), + ("green-emeraude", "Émeraude"), + ("green-menthe", "Menthe"), + ("green-archipel", "Archipel"), + ("blue-ecume", "Écume"), + ("blue-cumulus", "Cumulus"), + ("purple-glycine", "Glycine"), + ("pink-macaron", "Macaron"), + ("pink-tuile", "Tuile"), + ("yellow-tournesol", "Tournesol"), + ("yellow-moutarde", "Moutarde"), + ("orange-terre-battue", "Terre battue"), + ("brown-cafe-creme", "Café crème"), + ("brown-caramel", "Caramel"), + ("brown-opera", "Opéra"), + ("beige-gris-galet", "Gris galet"), + ], + "help_text": "Only for clickable tags", + "label": "Tag color", + "required": False, + }, + ), + 62: ( + "wagtail.blocks.StructBlock", + [[("page", 12), ("document", 13), ("external_url", 14)]], + {"required": False}, + ), + 63: ( + "wagtail.blocks.StructBlock", + [[("label", 28), ("is_small", 60), ("color", 61), ("icon_class", 32), ("link", 62)]], + {"label": "Tag"}, + ), + 64: ("wagtail.blocks.StreamBlock", [[("tag", 63)]], {"label": "Tag list"}), + 65: ( + "wagtail.blocks.StructBlock", + [ + [ + ("page", 12), + ("document", 13), + ("external_url", 14), + ("text", 15), + ("icon", 16), + ("size", 17), + ] + ], + {"label": "Single link"}, + ), + 66: ( + "wagtail.blocks.IntegerBlock", + (), + {"label": "Number of steps", "max_value": 8, "min_value": 1}, + ), + 67: ("wagtail.blocks.IntegerBlock", (), {"label": "Current step", "max_value": 8, "min_value": 1}), + 68: ("wagtail.blocks.TextBlock", (), {"label": "Detail"}), + 69: ("wagtail.blocks.StructBlock", [[("title", 28), ("detail", 68)]], {"label": "Step"}), + 70: ("wagtail.blocks.StreamBlock", [[("step", 69)]], {"label": "Steps"}), + 71: ( + "wagtail.blocks.StructBlock", + [[("title", 28), ("total", 66), ("current", 67), ("steps", 70)]], + {"group": "DSFR components", "label": "Stepper"}, + ), + 72: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-card--horizontal-tier", "1/3"), ("fr-card--horizontal-half", "50/50")], + "label": "Image ratio", + "required": False, + }, + ), + 73: ( + "wagtail.blocks.StreamBlock", + [[("badge", 58)]], + { + "help_text": "Only used if the card has an image.", + "label": "Image area badge", + "max_num": 1, + "required": False, + }, + ), + 74: ( + "wagtail.blocks.StructBlock", + [[("page", 12), ("document", 13), ("external_url", 14)]], + {"label": "Link", "required": False}, + ), + 75: ( + "wagtail.blocks.URLBlock", + (), + { + "group": "target", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "Link (obsolete)", + "required": False, + }, + ), + 76: ( + "wagtail.documents.blocks.DocumentChooserBlock", + (), + { + "group": "target", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "or Document (obsolete)", + "required": False, + }, + ), + 77: ("wagtail.blocks.CharBlock", (), {"label": "Top detail: text", "required": False}), + 78: ( + "content_manager.blocks.IconPickerBlock", + (), + {"label": "Top detail: icon", "required": False}, + ), + 79: ("wagtail.blocks.StreamBlock", [[("badge", 58)]], {}), + 80: ("wagtail.blocks.StreamBlock", [[("tag", 63)]], {}), + 81: ( + "wagtail.blocks.StreamBlock", + [[("badges", 79), ("tags", 80)]], + {"label": "Top detail: badges or tags", "max_num": 1, "required": False}, + ), + 82: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "Incompatible with the bottom call-to-action. If the card links to a downloadable document, the values are pre-filled.", + "label": "Bottom detail: text", + "required": False, + }, + ), + 83: ( + "content_manager.blocks.IconPickerBlock", + (), + {"label": "Bottom detail: icon", "required": False}, + ), + 84: ( + "wagtail.blocks.StructBlock", + [[("page", 12), ("document", 13), ("external_url", 14), ("text", 15)]], + {"label": "Link"}, + ), + 85: ("wagtail.blocks.StreamBlock", [[("link", 84)]], {}), + 86: ( + "wagtail.blocks.StructBlock", + [ + [ + ("page", 12), + ("document", 13), + ("external_url", 14), + ("text", 15), + ("button_type", 34), + ("icon_class", 32), + ("icon_side", 35), + ] + ], + {"label": "Button"}, + ), + 87: ( + "wagtail.blocks.StreamBlock", + [[("button", 86)]], + { + "help_text": "Please use only one primary button.\n If you use icons, use them on all buttons and align them on the same side.", + "label": "Buttons", + }, + ), + 88: ( + "wagtail.blocks.StreamBlock", + [[("links", 85), ("buttons", 87)]], + { + "help_text": "Incompatible with the bottom detail text.", + "label": "Bottom call-to-action: links or buttons", + "max_num": 1, + "required": False, + }, + ), + 89: ("wagtail.blocks.BooleanBlock", (), {"label": "Card with grey background", "required": False}), + 90: ("wagtail.blocks.BooleanBlock", (), {"label": "Card without background", "required": False}), + 91: ("wagtail.blocks.BooleanBlock", (), {"label": "Card without border", "required": False}), + 92: ("wagtail.blocks.BooleanBlock", (), {"label": "Card with a shadow", "required": False}), + 93: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 28), + ("heading_tag", 26), + ("description", 33), + ("image", 42), + ("image_ratio", 72), + ("image_badge", 73), + ("link", 74), + ("url", 75), + ("document", 76), + ("top_detail_text", 77), + ("top_detail_icon", 78), + ("top_detail_badges_tags", 81), + ("bottom_detail_text", 82), + ("bottom_detail_icon", 83), + ("call_to_action", 88), + ("grey_background", 89), + ("no_background", 90), + ("no_border", 91), + ("shadow", 92), + ] + ], + {"group": "DSFR components", "label": "Horizontal card"}, + ), + 94: ( + "wagtail.blocks.RichTextBlock", + (), + { + "features": ["bold", "italic", "superscript", "subscript", "strikethrough"], + "label": "Content", + "required": False, + }, + ), + 95: ( + "wagtail.images.blocks.ImageChooserBlock", + (), + {"help_text": "Prefer SVG files.", "label": "Image", "required": False}, + ), + 96: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "If the tile links to a downloadable document, the values are pre-filled.", + "label": "Detail text", + "required": False, + }, + ), + 97: ("wagtail.blocks.BooleanBlock", (), {"label": "Small tile", "required": False}), + 98: ("wagtail.blocks.BooleanBlock", (), {"label": "Tile with grey background", "required": False}), + 99: ("wagtail.blocks.BooleanBlock", (), {"label": "Tile without background", "required": False}), + 100: ("wagtail.blocks.BooleanBlock", (), {"label": "Tile without border", "required": False}), + 101: ("wagtail.blocks.BooleanBlock", (), {"label": "Tile with a shadow", "required": False}), + 102: ("wagtail.blocks.BooleanBlock", (), {"label": "Horizontal tile", "required": False}), + 103: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 28), + ("heading_tag", 26), + ("description", 94), + ("image", 95), + ("link", 74), + ("top_detail_badges_tags", 81), + ("detail_text", 96), + ("is_small", 97), + ("grey_background", 98), + ("no_background", 99), + ("no_border", 100), + ("shadow", 101), + ("is_horizontal", 102), + ] + ], + {"group": "DSFR components", "label": "Tile"}, + ), + 104: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 1), + ("heading_tag", 2), + ("image", 3), + ("alt", 4), + ("width", 5), + ("image_ratio", 6), + ("caption", 7), + ("url", 8), + ] + ], + {"label": "Image"}, + ), + 105: ("wagtail.blocks.RichTextBlock", (), {"label": "Rich text", "required": False}), + 106: ( + "wagtail.blocks.StreamBlock", + [[("buttons", 87)]], + {"label": "Call-to-action buttons", "max_num": 1, "required": False}, + ), + 107: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the CTA buttons above.", + "label": "Call to action label (obsolete)", + "required": False, + }, + ), + 108: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the CTA buttons above.", + "label": "Link (obsolete)", + "required": False, + }, + ), + 109: ( + "wagtail.blocks.StructBlock", + [[("text", 105), ("cta_buttons", 106), ("cta_label", 107), ("cta_url", 108)]], + {"label": "Text and call to action"}, + ), + 110: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "Accessibility: The title should describe, in a clear and concise manner, the embedded content.", + "label": "Title", + }, + ), + 111: ( + "wagtail.blocks.URLBlock", + (), + { + "help_text": "Example for Tally: https://tally.so/embed/w2jMRa", + "label": "URL of the iframe", + }, + ), + 112: ("wagtail.blocks.IntegerBlock", (), {"label": "Height (in pixels)"}), + 113: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "For example: \"allow='geolocation'\".", + "label": "Parameters", + "required": False, + }, + ), + 114: ( + "wagtail.blocks.StructBlock", + [[("title", 110), ("url", 111), ("height", 112), ("parameters", 113)]], + {"group": "DSFR components", "label": "Iframe"}, + ), + 115: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ("h5", "Heading 5"), + ], + "help_text": "Adapt to the page layout. Defaults to heading 2.", + "label": "Heading level", + "required": False, + }, + ), + 116: ( + "wagtail.blocks.PageChooserBlock", + (), + {"label": "Blog", "page_type": ["blog.BlogIndexPage"]}, + ), + 117: ( + "wagtail.blocks.IntegerBlock", + (), + { + "default": 3, + "label": "Number of entries", + "max_value": 8, + "min_value": 1, + "required": False, + }, + ), + 118: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("blog.Category",), + {"label": "Filter by category", "required": False}, + ), + 119: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("content_manager.Tag",), + {"label": "Filter by tag", "required": False}, + ), + 120: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("blog.Person",), + {"label": "Filter by author", "required": False}, + ), + 121: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("blog.Organization",), + { + "help_text": "The source is the organization of the post author", + "label": "Filter by source", + "required": False, + }, + ), + 122: ( + "wagtail.blocks.BooleanBlock", + (), + {"default": False, "label": "Show filters", "required": False}, + ), + 123: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 1), + ("heading_tag", 115), + ("blog", 116), + ("entries_count", 117), + ("category_filter", 118), + ("tag_filter", 119), + ("author_filter", 120), + ("source_filter", 121), + ("show_filters", 122), + ] + ], + {"group": "Website structure", "label": "Blog recent entries"}, + ), + 124: ( + "wagtail.blocks.PageChooserBlock", + (), + {"label": "Event calendar", "page_type": ["events.EventsIndexPage"]}, + ), + 125: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 1), + ("heading_tag", 115), + ("index_page", 124), + ("entries_count", 117), + ("category_filter", 118), + ("tag_filter", 119), + ("author_filter", 120), + ("source_filter", 121), + ("show_filters", 122), + ] + ], + {"group": "Website structure", "label": "Event calendar recent entries"}, + ), + 126: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "Incompatible with the bottom call-to-action.", + "label": "Bottom detail: text", + "required": False, + }, + ), + 127: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 28), + ("heading_tag", 26), + ("description", 33), + ("image", 42), + ("image_ratio", 6), + ("image_badge", 73), + ("link", 74), + ("url", 75), + ("document", 76), + ("top_detail_text", 77), + ("top_detail_icon", 78), + ("top_detail_badges_tags", 81), + ("bottom_detail_text", 126), + ("bottom_detail_icon", 83), + ("call_to_action", 88), + ("grey_background", 89), + ("no_background", 90), + ("no_border", 91), + ("shadow", 92), + ] + ], + {"group": "DSFR components", "label": "Vertical card"}, + ), + 128: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("blog.Person",), + { + "help_text": "Optional, all values can be manually specified or overriden below", + "label": "Person", + "required": False, + }, + ), + 129: ("wagtail.blocks.CharBlock", (), {"label": "Name", "max_length": 255, "required": False}), + 130: ("wagtail.blocks.CharBlock", (), {"label": "Role", "max_length": 255, "required": False}), + 131: ( + "wagtail.blocks.CharBlock", + (), + {"label": "Organization", "max_length": 255, "required": False}, + ), + 132: ( + "wagtail.blocks.CharBlock", + (), + {"label": "Contact info", "max_length": 500, "required": False}, + ), + 133: ("wagtail.blocks.StreamBlock", [[("tag", 63)]], {"label": "Tags", "required": False}), + 134: ( + "wagtail.blocks.StructBlock", + [ + [ + ("contact", 128), + ("link", 74), + ("heading_tag", 2), + ("name", 129), + ("role", 130), + ("organization", 131), + ("contact_info", 132), + ("image", 42), + ("tags", 133), + ] + ], + {"group": "Extra components", "label": "Contact card"}, + ), + 135: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 104), + ("video", 53), + ("transcription", 54), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("stepper", 71), + ("text_cta", 109), + ("link", 65), + ("iframe", 114), + ("tile", 103), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("card", 127), + ("contact_card", 134), + ] + ], + {"label": "Content"}, + ), + 136: ( + "wagtail.blocks.StructBlock", + [[("title", 28), ("content", 135)]], + {"label": "Tab", "max_num": 15, "min_num": 1}, + ), + 137: ( + "wagtail.blocks.StreamBlock", + [[("tabs", 136)]], + {"group": "DSFR components", "label": "Tabs"}, + ), + 138: ("wagtailmarkdown.blocks.MarkdownBlock", (), {"group": "Expert syntax", "label": "Markdown"}), + 139: ( + "wagtail.blocks.StructBlock", + [[("title", 110), ("url", 111), ("height", 112), ("parameters", 113)]], + {"group": "Expert syntax", "label": "Iframe"}, + ), + 140: ( + "wagtail.blocks.IntegerBlock", + (), + {"default": 3, "label": "Top margin", "max_value": 15, "min_value": 0}, + ), + 141: ( + "wagtail.blocks.IntegerBlock", + (), + {"default": 3, "label": "Bottom margin", "max_value": 15, "min_value": 0}, + ), + 142: ( + "wagtail.blocks.StructBlock", + [[("top_margin", 140), ("bottom_margin", 141)]], + {"group": "Page structure", "label": "Separator"}, + ), + 143: ( + "wagtail.images.blocks.ImageChooserBlock", + (), + {"label": "Background image", "required": False}, + ), + 144: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("Primary colors", [("blue-france", "Blue France"), ("red-marianne", "Red Marianne")]), + ("Neutral colors", [("grey", "Grey")]), + ( + "Illustration colors", + [ + ("green-tilleul-verveine", "Tilleul verveine"), + ("green-bourgeon", "Bourgeon"), + ("green-emeraude", "Émeraude"), + ("green-menthe", "Menthe"), + ("green-archipel", "Archipel"), + ("blue-ecume", "Écume"), + ("blue-cumulus", "Cumulus"), + ("purple-glycine", "Glycine"), + ("pink-macaron", "Macaron"), + ("pink-tuile", "Tuile"), + ("yellow-tournesol", "Tournesol"), + ("yellow-moutarde", "Moutarde"), + ("orange-terre-battue", "Terre battue"), + ("brown-cafe-creme", "Café crème"), + ("brown-caramel", "Caramel"), + ("brown-opera", "Opéra"), + ("beige-gris-galet", "Gris galet"), + ], + ), + ], + "help_text": "Uses the French Design System colors", + "label": "Background color", + "required": False, + }, + ), + 145: ( + "wagtail.blocks.RegexBlock", + (), + { + "error_messages": {"invalid": "Incorrect color format, must be #fff or #f5f5f5"}, + "help_text": "This field is obsolete and will be removed in the near future. Replace it with the background color.", + "label": "Background color, hexadecimal format (obsolete)", + "regex": "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$", + "required": False, + }, + ), + 146: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ("h5", "Heading 5"), + ("h6", "Heading 6"), + ("p", "Paragraph"), + ], + "help_text": "Adapt to the page layout. Defaults to heading 2.", + "label": "Heading level", + "required": False, + }, + ), + 147: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("3", "3/12"), + ("4", "4/12"), + ("5", "5/12"), + ("6", "6/12"), + ("7", "7/12"), + ("8", "8/12"), + ("9", "9/12"), + ], + "help_text": "The total width of all columns should be 12.", + "label": "Column width", + "required": False, + }, + ), + 148: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 104), + ("video", 53), + ("transcription", 54), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("stepper", 71), + ("text_cta", 109), + ("link", 65), + ("iframe", 114), + ("tile", 103), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("card", 127), + ("contact_card", 134), + ] + ], + {"label": "Column content"}, + ), + 149: ( + "wagtail.blocks.StructBlock", + [[("width", 147), ("content", 148)]], + {"group": "Page structure", "label": "Adjustable column"}, + ), + 150: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 104), + ("video", 53), + ("transcription", 54), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("stepper", 71), + ("text_cta", 109), + ("link", 65), + ("iframe", 114), + ("tile", 103), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("card", 127), + ("column", 149), + ] + ], + {"label": "Columns"}, + ), + 151: ( + "wagtail.blocks.StructBlock", + [ + [ + ("bg_image", 143), + ("bg_color_class", 144), + ("bg_color", 145), + ("title", 1), + ("heading_tag", 146), + ("columns", 150), + ] + ], + {"group": "Page structure", "label": "Multiple columns"}, + ), + 152: ( + "wagtail.blocks.ChoiceBlock", + [], + {"choices": [("3", "3/12"), ("4", "4/12"), ("6", "6/12")], "label": "Column width"}, + ), + 153: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 104), + ("video", 53), + ("transcription", 54), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("stepper", 71), + ("text_cta", 109), + ("link", 65), + ("iframe", 114), + ("tile", 103), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("card", 127), + ("contact_card", 134), + ] + ], + {"label": "Items"}, + ), + 154: ( + "wagtail.blocks.StructBlock", + [[("column_width", 152), ("items", 153)]], + {"group": "Page structure", "label": "Item grid"}, + ), + 155: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 104), + ("video", 53), + ("transcription", 54), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("stepper", 71), + ("text_cta", 109), + ("link", 65), + ("iframe", 114), + ("tile", 103), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("image_and_text", 22), + ("card", 93), + ("tabs", 137), + ("item_grid", 154), + ] + ], + {"label": "Content"}, + ), + 156: ( + "wagtail.blocks.StructBlock", + [[("bg_image", 143), ("bg_color_class", 144), ("content", 155)]], + {"group": "Page structure", "label": "Full width background"}, + ), + 157: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 104), + ("video", 53), + ("transcription", 54), + ("accordions", 31), + ("callout", 38), + ("highlight", 41), + ("quote", 46), + ("stepper", 71), + ("text_cta", 109), + ("link", 65), + ("iframe", 114), + ("tile", 103), + ("blog_recent_entries", 123), + ("events_recent_entries", 125), + ("image_and_text", 22), + ("card", 93), + ("tabs", 137), + ("item_grid", 154), + ] + ], + {"label": "Main content"}, + ), + 158: ("wagtail.blocks.CharBlock", (), {"label": "Side menu title", "required": False}), + 159: ( + "wagtail.blocks.RawHTMLBlock", + (), + { + "help_text": "Warning: Use HTML block with caution. Malicious code can compromise the security of the site.", + "label": "HTML", + }, + ), + 160: ("wagtail.blocks.PageChooserBlock", (), {"label": "Parent page"}), + 161: ("wagtail.blocks.StructBlock", [[("page", 160)]], {"label": "Page tree"}), + 162: ( + "wagtail.blocks.StreamBlock", + [[("html", 159), ("pagetree", 161)]], + {"label": "Side menu content"}, + ), + 163: ( + "wagtail.blocks.StructBlock", + [ + [ + ("bg_image", 143), + ("bg_color_class", 144), + ("main_content", 157), + ("sidemenu_title", 158), + ("sidemenu_content", 162), + ] + ], + {"group": "Page structure", "label": "Full width background with side menu"}, + ), + 164: ( + "wagtail.blocks.static_block.StaticBlock", + (), + { + "admin_text": "A simple, alphabetical list of the subpages of the current page.", + "group": "Website structure", + "label": "Subpages list", + "template": "content_manager/blocks/subpages_list.html", + }, + ), + 165: ( + "wagtail.blocks.RawHTMLBlock", + (), + { + "group": "Expert syntax", + "help_text": "Warning: Use HTML block with caution. Malicious code can compromise the security of the site.", + "readonly": True, + }, + ), + }, + ), + ), + migrations.AlterField( + model_name="category", + name="colophon", + field=wagtail.fields.StreamField( + [("paragraph", 0), ("imageandtext", 14), ("quote", 20), ("multicolumns", 134), ("contact_card", 138)], + blank=True, + block_lookup={ + 0: ("wagtail.blocks.RichTextBlock", (), {"label": "Rich text"}), + 1: ("wagtail.images.blocks.ImageChooserBlock", (), {"label": "Image"}), + 2: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("left", "Left"), ("right", "Right")], + "label": "Side where the image is displayed", + }, + ), + 3: ( + "wagtail.blocks.ChoiceBlock", + [], + {"choices": [("3", "3/12"), ("5", "5/12"), ("6", "6/12")], "label": "Image width"}, + ), + 4: ( + "wagtail.blocks.PageChooserBlock", + (), + { + "help_text": "Link to a page of this site. Use either this, the document, or the external URL parameter.", + "label": "Page", + "required": False, + }, + ), + 5: ( + "wagtail.documents.blocks.DocumentChooserBlock", + (), + { + "help_text": "Use either this, the external URL or the page parameter.", + "label": "Document", + "required": False, + }, + ), + 6: ( + "wagtail.blocks.URLBlock", + (), + { + "help_text": "Use either this, the document or the page parameter.", + "label": "External URL", + "required": False, + }, + ), + 7: ("wagtail.blocks.CharBlock", (), {"label": "Link label", "required": False}), + 8: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("", "No icon"), + ("fr-icon-arrow-right-line fr-link--icon-right", "Icon on the right side"), + ("fr-icon-arrow-right-line fr-link--icon-left", "Icon on the left side"), + ], + "help_text": "Only used for internal links.", + "label": "Icon", + "required": False, + }, + ), + 9: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-link--sm", "Small"), ("", "Medium"), ("fr-link--lg", "Large")], + "label": "Size", + "required": False, + }, + ), + 10: ( + "wagtail.blocks.StructBlock", + [[("page", 4), ("document", 5), ("external_url", 6), ("text", 7), ("icon", 8), ("size", 9)]], + { + "help_text": "The link is shown at the bottom of the text block, with an arrow", + "label": "Link", + "required": False, + }, + ), + 11: ( + "wagtail.blocks.CharBlock", + (), + { + "group": "obsolete", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "Link label (obsolete)", + "required": False, + }, + ), + 12: ( + "wagtail.blocks.PageChooserBlock", + (), + { + "group": "obsolete", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "Internal link (obsolete)", + "required": False, + }, + ), + 13: ( + "wagtail.blocks.URLBlock", + (), + { + "group": "obsolete", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "Link URL (obsolete)", + "required": False, + }, + ), + 14: ( + "wagtail.blocks.StructBlock", + [ + [ + ("image", 1), + ("image_side", 2), + ("image_ratio", 3), + ("text", 0), + ("link", 10), + ("link_label", 11), + ("page", 12), + ("link_url", 13), + ] + ], + {"label": "Bloc image et texte"}, + ), + 15: ("wagtail.images.blocks.ImageChooserBlock", (), {"label": "Image", "required": False}), + 16: ("wagtail.blocks.CharBlock", (), {"label": "Quote"}), + 17: ("wagtail.blocks.CharBlock", (), {"label": "Author name", "required": False}), + 18: ("wagtail.blocks.CharBlock", (), {"label": "Author title", "required": False}), + 19: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("green-tilleul-verveine", "Tilleul verveine"), + ("green-bourgeon", "Bourgeon"), + ("green-emeraude", "Émeraude"), + ("green-menthe", "Menthe"), + ("green-archipel", "Archipel"), + ("blue-ecume", "Écume"), + ("blue-cumulus", "Cumulus"), + ("purple-glycine", "Glycine"), + ("pink-macaron", "Macaron"), + ("pink-tuile", "Tuile"), + ("yellow-tournesol", "Tournesol"), + ("yellow-moutarde", "Moutarde"), + ("orange-terre-battue", "Terre battue"), + ("brown-cafe-creme", "Café crème"), + ("brown-caramel", "Caramel"), + ("brown-opera", "Opéra"), + ("beige-gris-galet", "Gris galet"), + ], + "label": "Color", + "required": False, + }, + ), + 20: ( + "wagtail.blocks.StructBlock", + [[("image", 15), ("quote", 16), ("author_name", 17), ("author_title", 18), ("color", 19)]], + {"label": "Citation"}, + ), + 21: ( + "wagtail.images.blocks.ImageChooserBlock", + (), + {"label": "Background image", "required": False}, + ), + 22: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("Primary colors", [("blue-france", "Blue France"), ("red-marianne", "Red Marianne")]), + ("Neutral colors", [("grey", "Grey")]), + ( + "Illustration colors", + [ + ("green-tilleul-verveine", "Tilleul verveine"), + ("green-bourgeon", "Bourgeon"), + ("green-emeraude", "Émeraude"), + ("green-menthe", "Menthe"), + ("green-archipel", "Archipel"), + ("blue-ecume", "Écume"), + ("blue-cumulus", "Cumulus"), + ("purple-glycine", "Glycine"), + ("pink-macaron", "Macaron"), + ("pink-tuile", "Tuile"), + ("yellow-tournesol", "Tournesol"), + ("yellow-moutarde", "Moutarde"), + ("orange-terre-battue", "Terre battue"), + ("brown-cafe-creme", "Café crème"), + ("brown-caramel", "Caramel"), + ("brown-opera", "Opéra"), + ("beige-gris-galet", "Gris galet"), + ], + ), + ], + "help_text": "Uses the French Design System colors", + "label": "Background color", + "required": False, + }, + ), + 23: ( + "wagtail.blocks.RegexBlock", + (), + { + "error_messages": {"invalid": "Incorrect color format, must be #fff or #f5f5f5"}, + "help_text": "This field is obsolete and will be removed in the near future. Replace it with the background color.", + "label": "Background color, hexadecimal format (obsolete)", + "regex": "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$", + "required": False, + }, + ), + 24: ("wagtail.blocks.CharBlock", (), {"label": "Title", "required": False}), + 25: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ("h5", "Heading 5"), + ("h6", "Heading 6"), + ("p", "Paragraph"), + ], + "help_text": "Adapt to the page layout. Defaults to heading 2.", + "label": "Heading level", + "required": False, + }, + ), + 26: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ("h5", "Heading 5"), + ("h6", "Heading 6"), + ("p", "Paragraph"), + ], + "help_text": "Adapt to the page layout. Defaults to heading 3.", + "label": "Heading level", + "required": False, + }, + ), + 27: ( + "wagtail.blocks.CharBlock", + (), + {"label": "Alternative text (textual description of the image)", "required": False}, + ), + 28: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("fr-content-media--sm", "Small"), + ("", "Medium"), + ("fr-content-media--lg", "Large"), + ], + "label": "Witdh", + "required": False, + }, + ), + 29: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("fr-ratio-32x9", "32x9"), + ("fr-ratio-16x9", "16x9"), + ("fr-ratio-3x2", "3x2"), + ("fr-ratio-4x3", "4x3"), + ("fr-ratio-1x1", "1x1"), + ("fr-ratio-3x4", "3x4"), + ("fr-ratio-2x3", "2x3"), + ], + "label": "Image ratio", + "required": False, + }, + ), + 30: ("wagtail.blocks.CharBlock", (), {"label": "Caption", "required": False}), + 31: ("wagtail.blocks.URLBlock", (), {"label": "Link", "required": False}), + 32: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 24), + ("heading_tag", 26), + ("image", 1), + ("alt", 27), + ("width", 28), + ("image_ratio", 29), + ("caption", 30), + ("url", 31), + ] + ], + {"label": "Image"}, + ), + 33: ("wagtail.blocks.CharBlock", (), {"label": "Video title", "required": False}), + 34: ( + "wagtail.blocks.URLBlock", + (), + { + "help_text": "Use embed format, with a version that doesn't require a consent banner if available. (e.g. : https://www.youtube-nocookie.com/embed/gLzXOViPX-0) For Youtube, use Embed video and check Enable privacy-enhanced mode.", + "label": "Video URL", + }, + ), + 35: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-ratio-16x9", "16x9"), ("fr-ratio-4x3", "4x3"), ("fr-ratio-1x1", "1x1")], + "label": "Video ratio", + "required": False, + }, + ), + 36: ( + "wagtail.blocks.CharBlock", + (), + {"default": "Transcription", "label": "Title", "required": False}, + ), + 37: ("wagtail.blocks.RichTextBlock", (), {"label": "Transcription content", "required": False}), + 38: ( + "wagtail.blocks.StructBlock", + [[("title", 36), ("content", 37)]], + {"label": "Transcription", "required": False}, + ), + 39: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 33), + ("caption", 30), + ("url", 34), + ("width", 28), + ("video_ratio", 35), + ("transcription", 38), + ] + ], + {"label": "Video"}, + ), + 40: ("wagtail.blocks.StructBlock", [[("title", 36), ("content", 37)]], {"label": "Transcription"}), + 41: ("wagtail.blocks.CharBlock", (), {"label": "Title"}), + 42: ("wagtail.blocks.RichTextBlock", (), {"label": "Content"}), + 43: ( + "wagtail.blocks.StructBlock", + [[("title", 41), ("content", 42)]], + {"label": "Accordion", "max_num": 15, "min_num": 1}, + ), + 44: ( + "wagtail.blocks.StreamBlock", + [[("title", 41), ("accordion", 43)]], + {"group": "DSFR components", "label": "Accordions"}, + ), + 45: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ("h5", "Heading 5"), + ("h6", "Heading 6"), + ("p", "Paragraph"), + ], + "help_text": "Adapt to the page layout. Defaults to heading 3.", + "label": "Heading level", + }, + ), + 46: ("content_manager.blocks.IconPickerBlock", (), {"label": "Icon", "required": False}), + 47: ( + "wagtail.blocks.RichTextBlock", + (), + { + "features": [ + "bold", + "italic", + "link", + "document-link", + "superscript", + "subscript", + "strikethrough", + ], + "label": "Content", + "required": False, + }, + ), + 48: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("fr-btn", "Primary"), + ("fr-btn fr-btn--secondary", "Secundary"), + ("fr-btn fr-btn--tertiary", "Tertiary"), + ("fr-btn fr-btn--tertiary-no-outline", "Tertiary without border"), + ], + "label": "Button type", + "required": False, + }, + ), + 49: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-btn--icon-left", "Left"), ("fr-btn--icon-right", "Right")], + "label": "Icon side", + "required": False, + }, + ), + 50: ( + "wagtail.blocks.StructBlock", + [ + [ + ("page", 4), + ("document", 5), + ("external_url", 6), + ("text", 7), + ("button_type", 48), + ("icon_class", 46), + ("icon_side", 49), + ] + ], + {"label": "Button", "required": False}, + ), + 51: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 24), + ("heading_tag", 45), + ("icon_class", 46), + ("text", 47), + ("button", 50), + ("color", 19), + ] + ], + {"group": "DSFR components", "label": "Callout"}, + ), + 52: ( + "wagtail.blocks.RichTextBlock", + (), + { + "features": [ + "bold", + "italic", + "link", + "document-link", + "superscript", + "subscript", + "strikethrough", + ], + "label": "Content", + }, + ), + 53: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [("fr-text--sm", "Small"), ("", "Medium"), ("fr-text--lg", "Large")], + "label": "Size", + "required": False, + }, + ), + 54: ( + "wagtail.blocks.StructBlock", + [[("text", 52), ("color", 19), ("size", 53)]], + {"group": "DSFR components", "label": "Highlight"}, + ), + 55: ( + "wagtail.blocks.StructBlock", + [[("image", 15), ("quote", 16), ("author_name", 17), ("author_title", 18), ("color", 19)]], + {"group": "DSFR components", "label": "Quote"}, + ), + 56: ( + "wagtail.blocks.IntegerBlock", + (), + {"label": "Number of steps", "max_value": 8, "min_value": 1}, + ), + 57: ("wagtail.blocks.IntegerBlock", (), {"label": "Current step", "max_value": 8, "min_value": 1}), + 58: ("wagtail.blocks.TextBlock", (), {"label": "Detail"}), + 59: ("wagtail.blocks.StructBlock", [[("title", 41), ("detail", 58)]], {"label": "Step"}), + 60: ("wagtail.blocks.StreamBlock", [[("step", 59)]], {"label": "Steps"}), + 61: ( + "wagtail.blocks.StructBlock", + [[("title", 41), ("total", 56), ("current", 57), ("steps", 60)]], + {"group": "DSFR components", "label": "Stepper"}, + ), + 62: ("wagtail.blocks.RichTextBlock", (), {"label": "Rich text", "required": False}), + 63: ( + "wagtail.blocks.StructBlock", + [ + [ + ("page", 4), + ("document", 5), + ("external_url", 6), + ("text", 7), + ("button_type", 48), + ("icon_class", 46), + ("icon_side", 49), + ] + ], + {"label": "Button"}, + ), + 64: ( + "wagtail.blocks.StreamBlock", + [[("button", 63)]], + { + "help_text": "Please use only one primary button.\n If you use icons, use them on all buttons and align them on the same side.", + "label": "Buttons", + }, + ), + 65: ( + "wagtail.blocks.StreamBlock", + [[("buttons", 64)]], + {"label": "Call-to-action buttons", "max_num": 1, "required": False}, + ), + 66: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the CTA buttons above.", + "label": "Call to action label (obsolete)", + "required": False, + }, + ), + 67: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the CTA buttons above.", + "label": "Link (obsolete)", + "required": False, + }, + ), + 68: ( + "wagtail.blocks.StructBlock", + [[("text", 62), ("cta_buttons", 65), ("cta_label", 66), ("cta_url", 67)]], + {"label": "Text and call to action"}, + ), + 69: ( + "wagtail.blocks.StructBlock", + [[("page", 4), ("document", 5), ("external_url", 6), ("text", 7), ("icon", 8), ("size", 9)]], + {"label": "Single link"}, + ), + 70: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "Accessibility: The title should describe, in a clear and concise manner, the embedded content.", + "label": "Title", + }, + ), + 71: ( + "wagtail.blocks.URLBlock", + (), + { + "help_text": "Example for Tally: https://tally.so/embed/w2jMRa", + "label": "URL of the iframe", + }, + ), + 72: ("wagtail.blocks.IntegerBlock", (), {"label": "Height (in pixels)"}), + 73: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "For example: \"allow='geolocation'\".", + "label": "Parameters", + "required": False, + }, + ), + 74: ( + "wagtail.blocks.StructBlock", + [[("title", 70), ("url", 71), ("height", 72), ("parameters", 73)]], + {"group": "DSFR components", "label": "Iframe"}, + ), + 75: ( + "wagtail.blocks.RichTextBlock", + (), + { + "features": ["bold", "italic", "superscript", "subscript", "strikethrough"], + "label": "Content", + "required": False, + }, + ), + 76: ( + "wagtail.images.blocks.ImageChooserBlock", + (), + {"help_text": "Prefer SVG files.", "label": "Image", "required": False}, + ), + 77: ( + "wagtail.blocks.StructBlock", + [[("page", 4), ("document", 5), ("external_url", 6)]], + {"label": "Link", "required": False}, + ), + 78: ("wagtail.blocks.CharBlock", (), {"label": "Badge label", "required": False}), + 79: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("", [("new", "New"), ("grey", "Grey")]), + ( + "System colors", + [ + ("info", "Info"), + ("success", "Success"), + ("warning", "Warning"), + ("error", "Error"), + ], + ), + ( + "Illustration colors", + [ + ("green-tilleul-verveine", "Tilleul verveine"), + ("green-bourgeon", "Bourgeon"), + ("green-emeraude", "Émeraude"), + ("green-menthe", "Menthe"), + ("green-archipel", "Archipel"), + ("blue-ecume", "Écume"), + ("blue-cumulus", "Cumulus"), + ("purple-glycine", "Glycine"), + ("pink-macaron", "Macaron"), + ("pink-tuile", "Tuile"), + ("yellow-tournesol", "Tournesol"), + ("yellow-moutarde", "Moutarde"), + ("orange-terre-battue", "Terre battue"), + ("brown-cafe-creme", "Café crème"), + ("brown-caramel", "Caramel"), + ("brown-opera", "Opéra"), + ("beige-gris-galet", "Gris galet"), + ], + ), + ], + "label": "Badge color", + "required": False, + }, + ), + 80: ("wagtail.blocks.BooleanBlock", (), {"label": "Hide badge icon", "required": False}), + 81: ( + "wagtail.blocks.StructBlock", + [[("text", 78), ("color", 79), ("hide_icon", 80)]], + {"label": "Badge"}, + ), + 82: ("wagtail.blocks.StreamBlock", [[("badge", 81)]], {}), + 83: ("wagtail.blocks.BooleanBlock", (), {"label": "Small tag", "required": False}), + 84: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("green-tilleul-verveine", "Tilleul verveine"), + ("green-bourgeon", "Bourgeon"), + ("green-emeraude", "Émeraude"), + ("green-menthe", "Menthe"), + ("green-archipel", "Archipel"), + ("blue-ecume", "Écume"), + ("blue-cumulus", "Cumulus"), + ("purple-glycine", "Glycine"), + ("pink-macaron", "Macaron"), + ("pink-tuile", "Tuile"), + ("yellow-tournesol", "Tournesol"), + ("yellow-moutarde", "Moutarde"), + ("orange-terre-battue", "Terre battue"), + ("brown-cafe-creme", "Café crème"), + ("brown-caramel", "Caramel"), + ("brown-opera", "Opéra"), + ("beige-gris-galet", "Gris galet"), + ], + "help_text": "Only for clickable tags", + "label": "Tag color", + "required": False, + }, + ), + 85: ( + "wagtail.blocks.StructBlock", + [[("page", 4), ("document", 5), ("external_url", 6)]], + {"required": False}, + ), + 86: ( + "wagtail.blocks.StructBlock", + [[("label", 41), ("is_small", 83), ("color", 84), ("icon_class", 46), ("link", 85)]], + {"label": "Tag"}, + ), + 87: ("wagtail.blocks.StreamBlock", [[("tag", 86)]], {}), + 88: ( + "wagtail.blocks.StreamBlock", + [[("badges", 82), ("tags", 87)]], + {"label": "Top detail: badges or tags", "max_num": 1, "required": False}, + ), + 89: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "If the tile links to a downloadable document, the values are pre-filled.", + "label": "Detail text", + "required": False, + }, + ), + 90: ("wagtail.blocks.BooleanBlock", (), {"label": "Small tile", "required": False}), + 91: ("wagtail.blocks.BooleanBlock", (), {"label": "Tile with grey background", "required": False}), + 92: ("wagtail.blocks.BooleanBlock", (), {"label": "Tile without background", "required": False}), + 93: ("wagtail.blocks.BooleanBlock", (), {"label": "Tile without border", "required": False}), + 94: ("wagtail.blocks.BooleanBlock", (), {"label": "Tile with a shadow", "required": False}), + 95: ("wagtail.blocks.BooleanBlock", (), {"label": "Horizontal tile", "required": False}), + 96: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 41), + ("heading_tag", 45), + ("description", 75), + ("image", 76), + ("link", 77), + ("top_detail_badges_tags", 88), + ("detail_text", 89), + ("is_small", 90), + ("grey_background", 91), + ("no_background", 92), + ("no_border", 93), + ("shadow", 94), + ("is_horizontal", 95), + ] + ], + {"group": "DSFR components", "label": "Tile"}, + ), + 97: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("h2", "Heading 2"), + ("h3", "Heading 3"), + ("h4", "Heading 4"), + ("h5", "Heading 5"), + ], + "help_text": "Adapt to the page layout. Defaults to heading 2.", + "label": "Heading level", + "required": False, + }, + ), + 98: ( + "wagtail.blocks.PageChooserBlock", + (), + {"label": "Blog", "page_type": ["blog.BlogIndexPage"]}, + ), + 99: ( + "wagtail.blocks.IntegerBlock", + (), + { + "default": 3, + "label": "Number of entries", + "max_value": 8, + "min_value": 1, + "required": False, + }, + ), + 100: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("blog.Category",), + {"label": "Filter by category", "required": False}, + ), + 101: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("content_manager.Tag",), + {"label": "Filter by tag", "required": False}, + ), + 102: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("blog.Person",), + {"label": "Filter by author", "required": False}, + ), + 103: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("blog.Organization",), + { + "help_text": "The source is the organization of the post author", + "label": "Filter by source", + "required": False, + }, + ), + 104: ( + "wagtail.blocks.BooleanBlock", + (), + {"default": False, "label": "Show filters", "required": False}, + ), + 105: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 24), + ("heading_tag", 97), + ("blog", 98), + ("entries_count", 99), + ("category_filter", 100), + ("tag_filter", 101), + ("author_filter", 102), + ("source_filter", 103), + ("show_filters", 104), + ] + ], + {"group": "Website structure", "label": "Blog recent entries"}, + ), + 106: ( + "wagtail.blocks.PageChooserBlock", + (), + {"label": "Event calendar", "page_type": ["events.EventsIndexPage"]}, + ), + 107: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 24), + ("heading_tag", 97), + ("index_page", 106), + ("entries_count", 99), + ("category_filter", 100), + ("tag_filter", 101), + ("author_filter", 102), + ("source_filter", 103), + ("show_filters", 104), + ] + ], + {"group": "Website structure", "label": "Event calendar recent entries"}, + ), + 108: ( + "wagtail.blocks.StreamBlock", + [[("badge", 81)]], + { + "help_text": "Only used if the card has an image.", + "label": "Image area badge", + "max_num": 1, + "required": False, + }, + ), + 109: ( + "wagtail.blocks.URLBlock", + (), + { + "group": "target", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "Link (obsolete)", + "required": False, + }, + ), + 110: ( + "wagtail.documents.blocks.DocumentChooserBlock", + (), + { + "group": "target", + "help_text": "This field is obsolete and will be removed in the near future. Please replace with the Link field above.", + "label": "or Document (obsolete)", + "required": False, + }, + ), + 111: ("wagtail.blocks.CharBlock", (), {"label": "Top detail: text", "required": False}), + 112: ( + "content_manager.blocks.IconPickerBlock", + (), + {"label": "Top detail: icon", "required": False}, + ), + 113: ( + "wagtail.blocks.CharBlock", + (), + { + "help_text": "Incompatible with the bottom call-to-action.", + "label": "Bottom detail: text", + "required": False, + }, + ), + 114: ( + "content_manager.blocks.IconPickerBlock", + (), + {"label": "Bottom detail: icon", "required": False}, + ), + 115: ( + "wagtail.blocks.StructBlock", + [[("page", 4), ("document", 5), ("external_url", 6), ("text", 7)]], + {"label": "Link"}, + ), + 116: ("wagtail.blocks.StreamBlock", [[("link", 115)]], {}), + 117: ( + "wagtail.blocks.StreamBlock", + [[("links", 116), ("buttons", 64)]], + { + "help_text": "Incompatible with the bottom detail text.", + "label": "Bottom call-to-action: links or buttons", + "max_num": 1, + "required": False, + }, + ), + 118: ( + "wagtail.blocks.BooleanBlock", + (), + {"label": "Card with grey background", "required": False}, + ), + 119: ("wagtail.blocks.BooleanBlock", (), {"label": "Card without background", "required": False}), + 120: ("wagtail.blocks.BooleanBlock", (), {"label": "Card without border", "required": False}), + 121: ("wagtail.blocks.BooleanBlock", (), {"label": "Card with a shadow", "required": False}), + 122: ( + "wagtail.blocks.StructBlock", + [ + [ + ("title", 41), + ("heading_tag", 45), + ("description", 47), + ("image", 15), + ("image_ratio", 29), + ("image_badge", 108), + ("link", 77), + ("url", 109), + ("document", 110), + ("top_detail_text", 111), + ("top_detail_icon", 112), + ("top_detail_badges_tags", 88), + ("bottom_detail_text", 113), + ("bottom_detail_icon", 114), + ("call_to_action", 117), + ("grey_background", 118), + ("no_background", 119), + ("no_border", 120), + ("shadow", 121), + ] + ], + {"group": "DSFR components", "label": "Vertical card"}, + ), + 123: ( + "wagtail.blocks.ChoiceBlock", + [], + { + "choices": [ + ("3", "3/12"), + ("4", "4/12"), + ("5", "5/12"), + ("6", "6/12"), + ("7", "7/12"), + ("8", "8/12"), + ("9", "9/12"), + ], + "help_text": "The total width of all columns should be 12.", + "label": "Column width", + "required": False, + }, + ), + 124: ( + "wagtail.snippets.blocks.SnippetChooserBlock", + ("blog.Person",), + { + "help_text": "Optional, all values can be manually specified or overriden below", + "label": "Person", + "required": False, + }, + ), + 125: ("wagtail.blocks.CharBlock", (), {"label": "Name", "max_length": 255, "required": False}), + 126: ("wagtail.blocks.CharBlock", (), {"label": "Role", "max_length": 255, "required": False}), + 127: ( + "wagtail.blocks.CharBlock", + (), + {"label": "Organization", "max_length": 255, "required": False}, + ), + 128: ( + "wagtail.blocks.CharBlock", + (), + {"label": "Contact info", "max_length": 500, "required": False}, + ), + 129: ("wagtail.blocks.StreamBlock", [[("tag", 86)]], {"label": "Tags", "required": False}), + 130: ( + "wagtail.blocks.StructBlock", + [ + [ + ("contact", 124), + ("link", 77), + ("heading_tag", 26), + ("name", 125), + ("role", 126), + ("organization", 127), + ("contact_info", 128), + ("image", 15), + ("tags", 129), + ] + ], + {"group": "Extra components", "label": "Contact card"}, + ), + 131: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 32), + ("video", 39), + ("transcription", 40), + ("accordions", 44), + ("callout", 51), + ("highlight", 54), + ("quote", 55), + ("stepper", 61), + ("text_cta", 68), + ("link", 69), + ("iframe", 74), + ("tile", 96), + ("blog_recent_entries", 105), + ("events_recent_entries", 107), + ("card", 122), + ("contact_card", 130), + ] + ], + {"label": "Column content"}, + ), + 132: ( + "wagtail.blocks.StructBlock", + [[("width", 123), ("content", 131)]], + {"group": "Page structure", "label": "Adjustable column"}, + ), + 133: ( + "wagtail.blocks.StreamBlock", + [ + [ + ("text", 0), + ("image", 32), + ("video", 39), + ("transcription", 40), + ("accordions", 44), + ("callout", 51), + ("highlight", 54), + ("quote", 55), + ("stepper", 61), + ("text_cta", 68), + ("link", 69), + ("iframe", 74), + ("tile", 96), + ("blog_recent_entries", 105), + ("events_recent_entries", 107), + ("card", 122), + ("column", 132), + ] + ], + {"label": "Columns"}, + ), + 134: ( + "wagtail.blocks.StructBlock", + [ + [ + ("bg_image", 21), + ("bg_color_class", 22), + ("bg_color", 23), + ("title", 24), + ("heading_tag", 25), + ("columns", 133), + ] + ], + {"label": "Multi-colonnes"}, + ), + 135: ("wagtail.blocks.CharBlock", (), {"label": "Name", "max_length": 255}), + 136: ("wagtail.blocks.CharBlock", (), {"label": "Role", "max_length": 255}), + 137: ("wagtail.blocks.CharBlock", (), {"label": "Organization", "max_length": 255}), + 138: ( + "wagtail.blocks.StructBlock", + [[("name", 135), ("role", 136), ("organization", 137), ("contact_info", 128), ("image", 1)]], + {"label": "Contact card"}, + ), + }, + help_text="Text displayed at the end of every page in the category", + ), + ), + ] diff --git a/blog/models.py b/blog/models.py index 96b85a2f..3cca040f 100644 --- a/blog/models.py +++ b/blog/models.py @@ -5,21 +5,23 @@ from django.db import models from django.db.models import BooleanField, Count, QuerySet from django.db.models.expressions import F +from django.http import HttpRequest, HttpResponse from django.shortcuts import get_object_or_404 from django.template.defaultfilters import slugify -from django.urls import reverse -from django.utils import timezone -from django.utils.translation import get_language, gettext_lazy as _ +from django.utils import feedgenerator, timezone +from django.utils.translation import gettext_lazy as _ from modelcluster.fields import ParentalKey, ParentalManyToManyField from modelcluster.tags import ClusterTaggableManager from rest_framework import serializers from taggit.models import TaggedItemBase +from unidecode import unidecode from wagtail.admin.panels import FieldPanel, FieldRowPanel, MultiFieldPanel, TitleFieldPanel from wagtail.admin.widgets.slug import SlugInput from wagtail.api import APIField +from wagtail.contrib.routable_page.models import RoutablePageMixin, path from wagtail.fields import RichTextField, StreamField from wagtail.models import Orderable -from wagtail.models.i18n import Locale, TranslatableMixin +from wagtail.models.i18n import TranslatableMixin from wagtail.search import index from wagtail.snippets.models import register_snippet @@ -192,13 +194,19 @@ class TagEntryPage(TaggedItemBase): content_object = ParentalKey("BlogEntryPage", related_name="entry_tags") -class BlogIndexPage(SitesFacilesBasePage): +class BlogIndexPage(RoutablePageMixin, SitesFacilesBasePage): posts_per_page = models.PositiveSmallIntegerField( default=10, validators=[MaxValueValidator(100), MinValueValidator(1)], verbose_name=_("Posts per page"), ) + feed_posts_limit = models.PositiveSmallIntegerField( + default=20, + validators=[MaxValueValidator(100), MinValueValidator(1)], + verbose_name=_("Post limit in the RSS/Atom feeds"), + ) + # Filters filter_by_category = models.BooleanField(_("Filter by category"), default=True) filter_by_tag = models.BooleanField(_("Filter by tag"), default=True) @@ -209,6 +217,7 @@ class BlogIndexPage(SitesFacilesBasePage): settings_panels = SitesFacilesBasePage.settings_panels + [ FieldPanel("posts_per_page"), + FieldPanel("feed_posts_limit"), MultiFieldPanel( [ FieldPanel("filter_by_category"), @@ -234,16 +243,14 @@ def posts(self): ) return posts - def get_context(self, request, tag=None, category=None, author=None, source=None, year=None, *args, **kwargs): + def get_context(self, request, *args, **kwargs): context = super(BlogIndexPage, self).get_context(request, *args, **kwargs) posts = self.posts - locale = Locale.objects.get(language_code=get_language()) extra_breadcrumbs = None extra_title = "" - if tag is None: - tag = request.GET.get("tag") + tag = request.GET.get("tag") if tag: tag = get_object_or_404(Tag, slug=tag) posts = posts.filter(tags=tag) @@ -251,7 +258,7 @@ def get_context(self, request, tag=None, category=None, author=None, source=None "links": [ {"url": self.get_url(), "title": self.title}, { - "url": reverse("blog:tags_list", kwargs={"blog_slug": self.slug}), + "url": f"{self.get_url()}{self.reverse_subpage('tags_list')}", "title": _("Tags"), }, ], @@ -259,17 +266,16 @@ def get_context(self, request, tag=None, category=None, author=None, source=None } extra_title = _("Posts tagged with %(tag)s") % {"tag": tag} - if category is None: - category = request.GET.get("category") + category = request.GET.get("category") if category: - category = get_object_or_404(Category, slug=category, locale=locale) + category = get_object_or_404(Category, slug=category, locale=self.locale) posts = posts.filter(blog_categories=category) extra_breadcrumbs = { "links": [ {"url": self.get_url(), "title": self.title}, { - "url": reverse("blog:categories_list", kwargs={"blog_slug": self.slug}), + "url": f"{self.get_url()}{self.reverse_subpage('categories_list')}", "title": _("Categories"), }, ], @@ -277,8 +283,7 @@ def get_context(self, request, tag=None, category=None, author=None, source=None } extra_title = _("Posts in category %(category)s") % {"category": category.name} - if source is None: - source = request.GET.get("source") + source = request.GET.get("source") if source: source = get_object_or_404(Organization, slug=source) posts = posts.filter(authors__organization=source) @@ -290,8 +295,7 @@ def get_context(self, request, tag=None, category=None, author=None, source=None } extra_title = _("Posts written by") + f" {source.name}" - if author is None: - author = request.GET.get("author") + author = request.GET.get("author") if author: author = get_object_or_404(Person, id=author) @@ -304,6 +308,7 @@ def get_context(self, request, tag=None, category=None, author=None, source=None posts = posts.filter(authors=author) extra_title = _("Posts written by") + f" {author.name}" + year = request.GET.get("year") if year: posts = posts.filter(date__year=year) extra_title = _("Posts published in %(year)s") % {"year": year} @@ -380,6 +385,129 @@ def list_tags(self, min_count: int = 1) -> list: def show_filters(self) -> bool | BooleanField: return self.filter_by_category or self.filter_by_tag or self.filter_by_author or self.filter_by_source + def feed_posts(self, feed, request): + """ + Returns the posts for a RSS or ATOM feed relative to the parameters + """ + posts = self.posts + + category = request.GET.get("category") + if category: + category = get_object_or_404(Category, slug=category, locale=self.locale) + posts = posts.filter(blog_categories=category) + + limit = int(request.GET.get("limit", self.feed_posts_limit)) + posts = posts[:limit] + + for post in posts: + feed.add_item( + post.title, + post.full_url, + pubdate=post.date, + description=post.search_description, + ) + + return feed + + @path("rss/", name="rss_feed") + def rss_view(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: + """ + Return the current blog as a RSS feed + """ + + if self.seo_title: + title = self.seo_title + else: + title = self.title + + feed = feedgenerator.Rss201rev2Feed( + title=title, + link=self.full_url, + description=self.search_description, + language=self.locale.language_code, + feed_url=f"{self.full_url}{self.reverse_subpage('rss_feed')}", + ) + feed = self.feed_posts(feed, request) + + response = HttpResponse(feed.writeString("UTF-8"), content_type="application/xml") + return response + + @path("atom/", name="atom_feed") + def atom_view(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: + """ + Return the current blog as an Atom feed + """ + + if self.seo_title: + title = self.seo_title + else: + title = self.title + + feed = feedgenerator.Atom1Feed( + title=title, + link=self.full_url, + description=self.search_description, + language=self.locale.language_code, + feed_url=f"{self.full_url}{self.reverse_subpage('atom_feed')}", + ) + feed = self.feed_posts(feed, request) + + response = HttpResponse(feed.writeString("UTF-8"), content_type="application/xml") + return response + + @path("categories/", name="categories_list") + def categories_list(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: + extra_title = _("Categories") + categories = self.list_categories() + + extra_breadcrumbs = { + "links": [ + {"url": self.get_url(), "title": self.title}, + ], + "current": _("Categories"), + } + + return self.render( + request, + context_overrides={ + "categories": categories, + "page": self, + "extra_title": extra_title, + "extra_breadcrumbs": extra_breadcrumbs, + }, + template="blog/categories_list_page.html", + ) + + @path("tags/", name="tags_list") + def tags_list(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: + extra_title = _("Tags") + tags = self.list_tags() + + tags_by_first_letter = {} + for tag in tags: + first_letter = unidecode(tag["tag_slug"][0].upper()) + if first_letter not in tags_by_first_letter: + tags_by_first_letter[first_letter] = [] + tags_by_first_letter[first_letter].append(tag) + + extra_breadcrumbs = { + "links": [ + {"url": self.get_url(), "title": self.title}, + ], + "current": _("Tags"), + } + + return self.render( + request, + context_overrides={ + "sorted_tags": tags_by_first_letter, + "page": self, + "extra_title": extra_title, + "extra_breadcrumbs": extra_breadcrumbs, + }, + template="blog/tags_list_page.html", + ) + class BlogEntryPage(SitesFacilesBasePage): tags = ClusterTaggableManager(through="TagEntryPage", blank=True) diff --git a/blog/templates/blog/blocks/feeds.html b/blog/templates/blog/blocks/feeds.html new file mode 100644 index 00000000..b3d95651 --- /dev/null +++ b/blog/templates/blog/blocks/feeds.html @@ -0,0 +1,27 @@ + +{% load wagtailroutablepage_tags i18n %} + +
+ +
diff --git a/blog/templates/blog/blog_entry_page.html b/blog/templates/blog/blog_entry_page.html index 65157c5f..b8d5ea20 100644 --- a/blog/templates/blog/blog_entry_page.html +++ b/blog/templates/blog/blog_entry_page.html @@ -51,7 +51,12 @@
{% include "content_manager/blocks/breadcrumbs.html" %} -

{{ page.title }}

+ {% if not page.header_with_title %} +

+ {{ page.title }} + {% include "content_manager/blocks/page_visibility.html" %} +

+ {% endif %}

diff --git a/blog/templates/blog/blog_index_page.html b/blog/templates/blog/blog_index_page.html index ec187e8f..6170c9fe 100644 --- a/blog/templates/blog/blog_index_page.html +++ b/blog/templates/blog/blog_index_page.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load static dsfr_tags wagtailcore_tags wagtailimages_tags wagtail_dsfr_tags i18n %} +{% load static dsfr_tags wagtailcore_tags wagtailimages_tags wagtailroutablepage_tags wagtail_dsfr_tags i18n %} {% block title %} {{ page.seo_title|default:page.title }} — {{ settings.content_manager.CmsDsfrConfig.site_title }} @@ -19,6 +19,14 @@ + + {% if page.get_translations.live %} {% for translation in page.get_translations.live %} @@ -145,6 +153,7 @@

{% translate "Filter by source" %}

{% if posts.paginator.num_pages > 1 %}
{% dsfr_pagination posts %}
{% endif %} + {% include "blog/blocks/feeds.html" %} {% else %} @@ -152,6 +161,7 @@

{% translate "Filter by source" %}

{% if posts.paginator.num_pages > 1 %}
{% dsfr_pagination posts %}
{% endif %} + {% include "blog/blocks/feeds.html" %} {% endif %} {% endblock content %} diff --git a/blog/templates/blog/categories_list_page.html b/blog/templates/blog/categories_list_page.html index 9750c4e6..72729f73 100644 --- a/blog/templates/blog/categories_list_page.html +++ b/blog/templates/blog/categories_list_page.html @@ -16,8 +16,13 @@ {% include "content_manager/blocks/messages.html" %}
- {% dsfr_breadcrumb breadcrumb %} -

{% translate "Categories" %}

+ {% include "content_manager/blocks/breadcrumbs.html" %} + {% if not page.header_with_title %} +

+ {{ page.title }} + {% if extra_title %}: {{ extra_title }}{% endif %} +

+ {% endif %}