diff --git a/core/settings.py b/core/settings.py index 52480fce0..fc5f2e27d 100644 --- a/core/settings.py +++ b/core/settings.py @@ -364,3 +364,7 @@ def context_processors(): CONTACT_FORM = decouple.config( "CONTACT_FORM", default="https://tally.so/r/wzYveR", cast=str ) + +ASSISTANT_SURVEY_FORM = decouple.config( + "ASSISTANT_SURVEY_FORM", default="https://tally.so/r/wvNgx0", cast=str +) diff --git a/e2e_tests/accessibility.spec.ts b/e2e_tests/accessibility.spec.ts index a00cdf423..f41e19375 100644 --- a/e2e_tests/accessibility.spec.ts +++ b/e2e_tests/accessibility.spec.ts @@ -22,3 +22,13 @@ test("carte iFrame is WCAG compliant", async ({ page }) => { expect(accessibilityScanResults.violations).toEqual([]) }) + +// test("assistant is WCAG compliant", async ({ page }) => { +// await page.goto(`http://localhost:8000/dechet`, { waitUntil: "networkidle" }) + +// const accessibilityScanResults = await new AxeBuilder({ page }) +// .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']) // TODO : trouver quelle règle se rapproche le plus du RGAA +// .analyze() + +// expect(accessibilityScanResults.violations).toEqual([]) +// }) diff --git a/qfdmd/admin.py b/qfdmd/admin.py index 94595d167..921e3e98c 100644 --- a/qfdmd/admin.py +++ b/qfdmd/admin.py @@ -3,7 +3,16 @@ from import_export.admin import ImportExportModelAdmin from qfdmd.models import Lien, Produit, Suggestion, Synonyme -from qfdmo.admin.acteur import NotEditableInlineMixin + + +class LienResource(resources.ModelResource): + class Meta: + model = Lien + + +class ProduitResource(resources.ModelResource): + class Meta: + model = Produit class SynonymeResource(resources.ModelResource): @@ -32,7 +41,8 @@ class SuggestionAdmin(admin.ModelAdmin): @admin.register(Produit) -class ProduitAdmin(admin.ModelAdmin): +class ProduitAdmin(ImportExportModelAdmin, admin.ModelAdmin): + resource_class = ProduitResource list_display = ("nom", "id", "synonymes_existants") search_fields = ["nom", "id", "synonymes_existants"] # ajout des filtres de recherche sur bdd et code @@ -41,13 +51,14 @@ class ProduitAdmin(admin.ModelAdmin): @admin.register(Lien) -class LienAdmin(NotEditableInlineMixin, admin.ModelAdmin): +class LienAdmin(ImportExportModelAdmin, admin.ModelAdmin): + resource_class = LienResource list_display = ("titre_du_lien", "url", "description") inlines = [ProduitInline] @admin.register(Synonyme) -class SynonymeAdmin(NotEditableInlineMixin, ImportExportModelAdmin, admin.ModelAdmin): - resource_classes = [SynonymeResource] +class SynonymeAdmin(ImportExportModelAdmin, admin.ModelAdmin): + resource_class = SynonymeResource search_fields = ["nom"] list_display = ("nom", "produit", "slug") diff --git a/qfdmd/forms.py b/qfdmd/forms.py index bc1e44286..8ccc2c5df 100644 --- a/qfdmd/forms.py +++ b/qfdmd/forms.py @@ -1,10 +1,12 @@ import logging from django import forms +from django.contrib.postgres.lookups import Unaccent from django.contrib.postgres.search import ( TrigramSimilarity, TrigramStrictWordSimilarity, ) +from django.db.models import Case, F, Value, When from dsfr.forms import DsfrBaseForm from .models import Synonyme @@ -27,9 +29,21 @@ def search(self) -> dict[str, str]: Synonyme.objects.annotate( word_similarity=TrigramStrictWordSimilarity(search_query, "nom"), similarity=TrigramSimilarity("nom", search_query), + unaccented_nom=Unaccent("nom"), + boosted_score=Case( + When( + unaccented_nom__istartswith=search_query, + then=F("similarity") + Value(0.1), + ), + When( + unaccented_nom__iendswith=search_query, + then=F("similarity") + Value(0.05), + ), + default=F("similarity"), + ), ) .filter(word_similarity__gte=0.1) - .order_by("-word_similarity", "-similarity") + .order_by("-boosted_score", "-word_similarity", "-similarity") .values("slug", "nom")[:10] ) return self.results diff --git a/qfdmd/migrations/0015_remove_produit_picto_synonyme_picto.py b/qfdmd/migrations/0015_remove_produit_picto_synonyme_picto.py new file mode 100644 index 000000000..7db651940 --- /dev/null +++ b/qfdmd/migrations/0015_remove_produit_picto_synonyme_picto.py @@ -0,0 +1,22 @@ +# Generated by Django 5.1.1 on 2024-12-03 09:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("qfdmd", "0014_alter_suggestion_produit"), + ] + + operations = [ + migrations.RemoveField( + model_name="produit", + name="picto", + ), + migrations.AddField( + model_name="synonyme", + name="picto", + field=models.FileField(blank=True, null=True, upload_to="pictos"), + ), + ] diff --git a/qfdmd/migrations/0016_alter_produit_comment_les_eviter.py b/qfdmd/migrations/0016_alter_produit_comment_les_eviter.py new file mode 100644 index 000000000..73f97cd88 --- /dev/null +++ b/qfdmd/migrations/0016_alter_produit_comment_les_eviter.py @@ -0,0 +1,20 @@ +# Generated by Django 5.1.1 on 2024-12-04 12:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("qfdmd", "0015_remove_produit_picto_synonyme_picto"), + ] + + operations = [ + migrations.AlterField( + model_name="produit", + name="comment_les_eviter", + field=models.TextField( + blank=True, help_text="Comment consommer responsable ?" + ), + ), + ] diff --git a/qfdmd/migrations/0017_synonyme_pin_on_homepage.py b/qfdmd/migrations/0017_synonyme_pin_on_homepage.py new file mode 100644 index 000000000..2e5a6c19b --- /dev/null +++ b/qfdmd/migrations/0017_synonyme_pin_on_homepage.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.1 on 2024-12-04 13:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("qfdmd", "0016_alter_produit_comment_les_eviter"), + ] + + operations = [ + migrations.AddField( + model_name="synonyme", + name="pin_on_homepage", + field=models.BooleanField(default=False), + ), + ] diff --git a/qfdmd/migrations/0018_produit_qu_est_ce_que_j_en_fais_bon_etat_and_more.py b/qfdmd/migrations/0018_produit_qu_est_ce_que_j_en_fais_bon_etat_and_more.py new file mode 100644 index 000000000..13c251e3f --- /dev/null +++ b/qfdmd/migrations/0018_produit_qu_est_ce_que_j_en_fais_bon_etat_and_more.py @@ -0,0 +1,34 @@ +# Generated by Django 5.1.1 on 2024-12-04 13:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("qfdmd", "0017_synonyme_pin_on_homepage"), + ] + + operations = [ + migrations.AddField( + model_name="produit", + name="qu_est_ce_que_j_en_fais_bon_etat", + field=models.TextField( + blank=True, help_text="Qu'est-ce que j'en fais ? - Bon état" + ), + ), + migrations.AddField( + model_name="produit", + name="qu_est_ce_que_j_en_fais_mauvais_etat", + field=models.TextField( + blank=True, help_text="Qu'est-ce que j'en fais ? - Mauvais état" + ), + ), + migrations.AlterField( + model_name="produit", + name="qu_est_ce_que_j_en_fais", + field=models.TextField( + blank=True, help_text="Qu'est-ce que j'en fais ? - ANCIEN CHAMP" + ), + ), + ] diff --git a/qfdmd/migrations/0019_synonyme_meta_description_and_more.py b/qfdmd/migrations/0019_synonyme_meta_description_and_more.py new file mode 100644 index 000000000..629451fc8 --- /dev/null +++ b/qfdmd/migrations/0019_synonyme_meta_description_and_more.py @@ -0,0 +1,26 @@ +# Generated by Django 5.1.1 on 2024-12-04 14:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("qfdmd", "0018_produit_qu_est_ce_que_j_en_fais_bon_etat_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="synonyme", + name="meta_description", + field=models.TextField(default=""), + preserve_default=False, + ), + migrations.AlterField( + model_name="produit", + name="qu_est_ce_que_j_en_fais", + field=models.TextField( + blank=True, help_text="Qu'est-ce que j'en fais ? - ANCIEN CHAMP." + ), + ), + ] diff --git a/qfdmd/models.py b/qfdmd/models.py index 968c200ba..b3adade0a 100644 --- a/qfdmd/models.py +++ b/qfdmd/models.py @@ -1,4 +1,8 @@ +from urllib.parse import urlencode + +from django.conf import settings from django.contrib.gis.db import models +from django.template.loader import render_to_string from django.urls.base import reverse from django.utils.functional import cached_property from django_extensions.db.fields import AutoSlugField @@ -20,9 +24,22 @@ class Produit(models.Model): synonymes_existants = models.TextField(blank=True, help_text="Synonymes existants") code = models.CharField(blank=True, help_text="Code") bdd = models.CharField(blank=True, help_text="Bdd") - comment_les_eviter = models.TextField(blank=True, help_text="Comment les éviter ?") qu_est_ce_que_j_en_fais = models.TextField( - blank=True, help_text="Qu'est-ce que j'en fais ?" + blank=True, help_text="Qu'est-ce que j'en fais ? - ANCIEN CHAMP." + ) + # Le nom des champs conserve ici délibérément l'ancienne nomenclature, + # car le travail sur le nommage n'a pas encore été effectué. + # TODO : renommer ces champs lorsque le métier + technique seront tombés + # d'accord sur un nom pour ces champs + qu_est_ce_que_j_en_fais_mauvais_etat = models.TextField( + blank=True, help_text="Qu'est-ce que j'en fais ? - Mauvais état" + ) + # TODO : idem ci-dessus + qu_est_ce_que_j_en_fais_bon_etat = models.TextField( + blank=True, help_text="Qu'est-ce que j'en fais ? - Bon état" + ) + comment_les_eviter = models.TextField( + blank=True, help_text="Comment consommer responsable ?" ) que_va_t_il_devenir = models.TextField( blank=True, help_text="Que va-t-il devenir ?" @@ -30,7 +47,6 @@ class Produit(models.Model): nom_eco_organisme = models.TextField(blank=True, help_text="Nom de l’éco-organisme") filieres_rep = models.TextField(blank=True, help_text="Filière(s) REP concernée(s)") slug = models.CharField(blank=True, help_text="Slug - ne pas modifier") - picto = models.FileField(upload_to="pictos", blank=True, null=True) def __str__(self): return f"{self.id} - {self.nom}" @@ -39,6 +55,79 @@ def __str__(self): def sous_categorie_with_carte_display(self): return self.sous_categories.filter(afficher_carte=True).first() + def get_etats_descriptions(self) -> tuple[str, str] | None: + # TODO: rename this method + # Une fois que les fiches déchet auront toutes + # la notion de bon etat / mauvais état stockée en + # base de donnée au bon endroit, cette méthode deviendra caduque. + text = self.qu_est_ce_que_j_en_fais + if "En bon état" not in text and "En mauvais état" not in text: + return + + _, _, mauvais_etat_and_rest = text.partition("En bon état") + bon_etat, _, mauvais_etat = mauvais_etat_and_rest.partition( + "En mauvais état" + ) + + return (bon_etat, mauvais_etat) + + @cached_property + def mauvais_etat(self) -> str: + if self.qu_est_ce_que_j_en_fais_mauvais_etat: + return self.qu_est_ce_que_j_en_fais_mauvais_etat + try: + return self.get_etats_descriptions()[0] + except KeyError: + return "" + + @property + def carte_settings(self): + # TODO : gérer plusieurs catégories ici + sous_categorie = self.sous_categories.filter(afficher_carte=True).first() + return { + "carte": 1, + "direction": "jai", + "first_dir": "jai", + "limit": 25, + "sc_id": sous_categorie.id, + } + + def get_url_carte(self, actions=None): + carte_settings = self.carte_settings + if actions: + carte_settings.update( + action_list=actions, + action_displayed=actions, + ) + params = urlencode(carte_settings) + return f"{settings.BASE_URL}/?{params}" + + @cached_property + def url_carte_mauvais_etat(self): + actions = "reparer|trier" + return self.get_url_carte(actions) + + @cached_property + def url_carte_bon_etat(self): + actions = "preter|emprunter|louer|mettreenlocation|donner|echanger|revendre" + return self.get_url_carte(actions) + + @cached_property + def bon_etat(self) -> str: + if self.qu_est_ce_que_j_en_fais_bon_etat: + return self.qu_est_ce_que_j_en_fais_bon_etat + + try: + return self.get_etats_descriptions()[1] + except KeyError: + return "" + + @cached_property + def en_savoir_plus(self): + return render_to_string( + "components/produit/_en_savoir_plus.html", {"produit": self} + ) + @cached_property def content_display(self) -> list[dict[str, str]]: return [ @@ -57,7 +146,7 @@ def content_display(self) -> list[dict[str, str]]: { "id": "En savoir plus", "title": "En savoir plus", - "content": self.que_va_t_il_devenir, + "content": self.en_savoir_plus, }, ] if item["content"] @@ -82,6 +171,9 @@ class Synonyme(models.Model): produit = models.ForeignKey( Produit, related_name="synonymes", on_delete=models.CASCADE ) + picto = models.FileField(upload_to="pictos", blank=True, null=True) + pin_on_homepage = models.BooleanField(default=False) + meta_description = models.TextField() @property def url(self) -> str: diff --git a/qfdmd/templatetags/qfdmd_tags.py b/qfdmd/templatetags/qfdmd_tags.py index 2e097c78e..3c8cfdd33 100644 --- a/qfdmd/templatetags/qfdmd_tags.py +++ b/qfdmd/templatetags/qfdmd_tags.py @@ -1,23 +1,22 @@ from django import template +from django.utils.safestring import mark_safe register = template.Library() -@register.inclusion_tag("components/carte/carte.html", takes_context=True) -def carte_from(context, produit): - request = context["request"] - try: - return { - "carte_settings": produit.sous_categorie_with_carte_display.carte_settings.items(), # noqa: E501 - "request": request, - } - except AttributeError: - return {} - - @register.inclusion_tag("components/patchwork/patchwork.html") def patchwork(): - from qfdmd.models import Produit + from qfdmd.models import Synonyme - produits = Produit.objects.exclude(picto="").exclude(picto=None) + produits = ( + Synonyme.objects.exclude(picto="") + .exclude(picto=None) + .filter(pin_on_homepage=True) + ) return {"top": produits[:24], "left": produits[24:30], "right": produits[30:36]} + + +@register.simple_tag +def render_file_content(svg_file): + with svg_file.open() as f: + return mark_safe(f.read().decode("utf-8")) diff --git a/qfdmd/urls.py b/qfdmd/urls.py index e0c9f86e6..9698c7300 100644 --- a/qfdmd/urls.py +++ b/qfdmd/urls.py @@ -1,4 +1,6 @@ +from django.conf import settings from django.urls import path +from django.views.generic import RedirectView from qfdmd.views import HomeView, SynonymeDetailView, search_view @@ -6,4 +8,11 @@ path("dechet/", HomeView.as_view(), name="home"), path("dechet/recherche", search_view, name="search"), path("dechet//", SynonymeDetailView.as_view(), name="synonyme-detail"), + path( + "assistant-enquete", + RedirectView.as_view( + url=settings.ASSISTANT_SURVEY_FORM, query_string=True, permanent=True + ), + name="assistant-survey-form", + ), ] diff --git a/qfdmd/views.py b/qfdmd/views.py index ad5aeca36..2228a47de 100644 --- a/qfdmd/views.py +++ b/qfdmd/views.py @@ -49,6 +49,24 @@ class HomeView(BaseView, ListView): template_name = "qfdmd/home.html" model = Suggestion + def get_context_data(self, **kwargs: Any) -> dict[str, Any]: + context = super().get_context_data(**kwargs) + context.update( + accordion={ + "id": "professionels", + "title": "Je suis un professionnel", + "content": "Actuellement, l’ensemble des recommandations ne concerne " + "que les particuliers. Pour des informations à destination des " + "professionnels, veuillez consulter le site " + "" + "https://economie-circulaire.ademe.fr/dechets-activites-economiques" + ".", + } + ) + return context + class SynonymeDetailView(BaseView, DetailView): model = Synonyme diff --git a/qfdmo/views/adresses.py b/qfdmo/views/adresses.py index e68730df4..704096a82 100644 --- a/qfdmo/views/adresses.py +++ b/qfdmo/views/adresses.py @@ -130,9 +130,7 @@ def get_initial(self): initial["ess"] = self.request.GET.get("ess") # TODO: refacto forms : delete this line initial["bounding_box"] = self.request.GET.get("bounding_box") - initial["sc_id"] = ( - self.request.GET.get("sc_id") if initial["sous_categorie_objet"] else None - ) + initial["sc_id"] = self.request.GET.get("sc_id") # Action to display and check action_displayed = self._set_action_displayed() @@ -472,8 +470,9 @@ def _compile_acteurs_queryset( filters &= Q(labels__bonus=True) if sous_categorie_id := self.get_data_from_request_or_bounded_form("sc_id", 0): + logger.info(f"{sous_categorie_id=}") filters &= Q( - proposition_services__sous_categories__id=sous_categorie_id, + proposition_services__sous_categories__id__in=[sous_categorie_id], ) actions_filters = Q() diff --git a/static/to_collect/assistant/agir-pour-la-transition.svg b/static/to_collect/assistant/agir-pour-la-transition.svg new file mode 100644 index 000000000..47e9dd59f --- /dev/null +++ b/static/to_collect/assistant/agir-pour-la-transition.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/templates/components/header/_bloc_marque.html b/static/to_collect/assistant/bloc-marque.svg similarity index 100% rename from templates/components/header/_bloc_marque.html rename to static/to_collect/assistant/bloc-marque.svg diff --git a/static/to_compile/entrypoints/qfdmd.css b/static/to_compile/entrypoints/qfdmd.css index 6d224b417..644d92e4c 100644 --- a/static/to_compile/entrypoints/qfdmd.css +++ b/static/to_compile/entrypoints/qfdmd.css @@ -6,13 +6,22 @@ @layer base { p a { - @apply qf-text-blue-france-sun-113-625; + @apply qf-text-blue-france-sun-113-625; + } + + /* Very temporary class to remove br at the top of bon etat / mauvais etat contents */ + .qf-without-extra-br { + br:first-child, + br:first-child+br { + @apply qf-hidden; + } } pre, code { - @apply qf-text-blue-france-sun-113-625 qf-font-bold; + @apply qf-text-blue-france-sun-113-625 qf-font-bold; } + } @layer components { @@ -40,7 +49,7 @@ } .middle { - @apply qf-px-7w qf-pt-5w; + @apply md:qf-px-7w qf-pt-5w; grid-area: middle; } @@ -90,3 +99,7 @@ } } + +.fr-footer__logo { + @apply qf-max-h-12w; +} diff --git a/templates/components/carte/carte.html b/templates/components/carte/carte.html deleted file mode 100644 index 14944f245..000000000 --- a/templates/components/carte/carte.html +++ /dev/null @@ -1,14 +0,0 @@ -{% load static %} -{% comment %} -The map is loaded using an iframe a the moment to mimic existing implementations. -In a near future, it will use a turbo frame instead. -{% endcomment %} - - -{{ context }} diff --git a/templates/components/footer/_dsfr_footer.html b/templates/components/footer/_dsfr_footer.html new file mode 100644 index 000000000..0f1d88fc6 --- /dev/null +++ b/templates/components/footer/_dsfr_footer.html @@ -0,0 +1,2 @@ +{% extends "dsfr/footer.html" %} +{% load static %} diff --git a/templates/components/footer/footer.html b/templates/components/footer/footer.html index 0bfb94e7d..ccc335ec9 100644 --- a/templates/components/footer/footer.html +++ b/templates/components/footer/footer.html @@ -1,39 +1,84 @@ - +

Vous souhaitez afficher ce simulateur sur votre site ? Personnalisez le et intégrez le facilement grâce à notre configurateur. + Vous souhaitez réutiliser le code du simulateur ? Ce simulateur est développé de manière ouverte (open source). L’ensemble du code est  + + disponible librement + . +

+ +
+

+ Qui sommes-nous ?

+

+ Que faire de mes déchets est un service public gratuit, porté par l’ + ADEME + l’incubateur de la DINUM + beta.gouv.fr + . + Notre mission est de diffuser les informations et données environnementales en open-data de l’ADEME pour encourager l’amélioration continue et l’innovation. Pour cela, nous accompagnons toutes les applications & services dans leur démarche responsable par l'appropriation et l’intégration de ces données afin d’apporter l’information au plus près des citoyens.

+
+
+

Comment contribuer au développement de nos outils ?

+

+ Pour contribuer à la conception et au développement de nos outils, rien de plus simple,  + à notre enquête + et renseignez votre adresse e-mail à la fin si vous le souhaitez, notre équipe vous recontactera pour vous présenter les dernières avancées et vous faire participer à des sessions de tests et de découvertes des fonctionnalités à venir ! Ce sera aussi l'occasion pour vous de nous faire part de vos retours d'expériences sur l'utilisation de nos outils. Votre participation est importante pour s'assurer que nous développons un outil pertinent et efficace pour vos besoins. +

+
+ +{% include "./_dsfr_footer.html" %} diff --git a/templates/components/header/header.html b/templates/components/header/header.html index bfd9179d9..abf03d198 100644 --- a/templates/components/header/header.html +++ b/templates/components/header/header.html @@ -1,14 +1,24 @@ -
- - {% include "./_bloc_marque.html" %} - +{% load static %} +
+
+ + + -
- {% include search_view_template_name %} + {% block header_search %} +
+ {% include search_view_template_name %} +
+ {% endblock header_search %}
+ + {% block header_post %} + {% endblock header_post %}
diff --git a/templates/components/header/header_home.html b/templates/components/header/header_home.html index acd520d32..291ac312f 100644 --- a/templates/components/header/header_home.html +++ b/templates/components/header/header_home.html @@ -1,5 +1,8 @@ +{% extends "./header.html" %} {% load qfdmd_tags %} -
- {% include "./_bloc_marque.html" %} - {% patchwork %} -
+ +{% block header_post %} +{% patchwork %} +{% endblock header_post %} + +{% block header_search %}{% endblock %} diff --git a/templates/components/lien/lien.html b/templates/components/lien/lien.html new file mode 100644 index 000000000..834d4b90e --- /dev/null +++ b/templates/components/lien/lien.html @@ -0,0 +1,11 @@ +
+ + {{ lien.titre_du_lien }} + + {{ lien.description }} +
diff --git a/templates/components/patchwork/_item.html b/templates/components/patchwork/_item.html index ae56ea6ed..1881f68bf 100644 --- a/templates/components/patchwork/_item.html +++ b/templates/components/patchwork/_item.html @@ -1,6 +1,7 @@ +{% load qfdmd_tags %} diff --git a/templates/components/patchwork/patchwork.html b/templates/components/patchwork/patchwork.html index c494dabe3..89bca86ee 100644 --- a/templates/components/patchwork/patchwork.html +++ b/templates/components/patchwork/patchwork.html @@ -10,7 +10,7 @@ {% endfor %}
-

+

Que faire de mes objets

diff --git a/templates/components/produit/_detail.html b/templates/components/produit/_detail.html new file mode 100644 index 000000000..5ee1552c9 --- /dev/null +++ b/templates/components/produit/_detail.html @@ -0,0 +1,16 @@ +
+
+ {{ content|default:produit.qu_est_ce_que_j_en_fais|safe }} +
+ + {% if produit.sous_categorie_with_carte_display %} +
+

Où l'apporter

+ +
+ {% endif %} +
diff --git a/templates/components/produit/_en_savoir_plus.html b/templates/components/produit/_en_savoir_plus.html new file mode 100644 index 000000000..9c08887b4 --- /dev/null +++ b/templates/components/produit/_en_savoir_plus.html @@ -0,0 +1,14 @@ +{% comment %} +Afin de tirer parti des composants DSFR de django-dsfr, ce template est rendu +In order to take advantage of django-dsfr components, this template is rendered +directly at the model-level. +It is not directly included, however in order to maintain consistency accross +templates, it is placed under the produit directory. +{% endcomment %} + +

En savoir plus

+
+ {% for lien in produit.liens.all %} + {% include "components/lien/lien.html" %} + {% endfor %} +
diff --git a/templates/components/produit/produit.html b/templates/components/produit/produit.html new file mode 100644 index 000000000..61371339e --- /dev/null +++ b/templates/components/produit/produit.html @@ -0,0 +1,46 @@ +{% load dsfr_tags %} + +{% if produit.bon_etat and produit.mauvais_etat %} +
+
    +
  • + +
  • +
  • + +
  • +
+
+ {% include "./_detail.html" with content=produit.mauvais_etat url_carte=produit.url_carte_mauvais_etat %} +
+
+ {% include "./_detail.html" with content=produit.bon_etat url_carte=produit.url_carte_bon_etat %} +
+
+{% else %} +
+ {% include "./_detail.html" %} +
+{% endif %} + + + +{% dsfr_accordion_group produit.content_display %} diff --git a/templates/components/search/view.html b/templates/components/search/view.html index e47a3946b..2a3253a0c 100644 --- a/templates/components/search/view.html +++ b/templates/components/search/view.html @@ -1,8 +1,11 @@
@@ -10,13 +13,18 @@ data-controller="search" data-turbo-frame="search-results" action="{% url 'qfdmd:search' %}" - class="qf-pl-4w {# should match the svg icon width #}" + class="qf-pl-4w {# should match the svg icon width #} + md:group-data-[home]:qf-h-7w + qf-h-5w + qf-content-center + " > {% csrf_token %} diff --git a/templates/components/sidebar/sidebar.html b/templates/components/sidebar/sidebar.html index ae23774bd..1e6677f0d 100644 --- a/templates/components/sidebar/sidebar.html +++ b/templates/components/sidebar/sidebar.html @@ -1,5 +1,6 @@
- {# accordion #} -
+
+ {% dsfr_accordion accordion %}
{% endblock main %} diff --git a/templates/qfdmd/synonyme_detail.html b/templates/qfdmd/synonyme_detail.html index 40bef9cff..0b3c2b439 100644 --- a/templates/qfdmd/synonyme_detail.html +++ b/templates/qfdmd/synonyme_detail.html @@ -1,5 +1,10 @@ {% extends "qfdmd/base.html" %} -{% load dsfr_tags qfdmd_tags %} + +{% block title %} +{{ block.super }} | {{ object.nom }} +{% endblock title %} + +{% block meta_description %}{{ object.meta_description|default:block.super }}{% endblock %} {% block main %} {% with object.produit as produit %} @@ -8,31 +13,13 @@ qf-gap-4w " > -
+

{{ object.nom|capfirst }}

-
- {% if produit.qu_est_ce_que_j_en_fais %} -
- {{ produit.qu_est_ce_que_j_en_fais|safe }} -
- {% endif %} - - {% if produit.sous_categorie_with_carte_display %} -
-

Où l'apporter

- {% carte_from produit %} -
- {% endif %} -
- - {% dsfr_accordion_group produit.content_display %} + {% include "components/produit/produit.html" %} {% endwith %} {% endblock main %}