{# ===== Meta SEO ===== #} {# ===== Open Graph / Facebook ===== #} {# ===== Twitter Card ===== #} {# ===== Schema.org markup ===== #} {# ===== Favicon ===== #} {# ===== Google Fonts - Poppins (primary) & Roboto (secondary) ===== #} {# GTM Consent Mode v2 — defaults refusés avant tout chargement #} {# Google Tag Manager #} {# Google Analytics (GA4) — gtag.js. Réutilise le gtag/dataLayer définis plus haut, donc le Consent Mode v2 (analytics refusé par défaut) s'applique aussi à cette propriété. #} {# ===== Styles - Tailwind via Encore + composants legacy ===== #} {% block stylesheets %} {{ encore_entry_link_tags('app') }} {% endblock %} {# Legacy CSS migrated to Tailwind - removed obsolete references #} {# ===== JavaScript ===== #} {% block javascripts %} {{ encore_entry_script_tags('app') }} {% endblock %} {# ===== Layout avec Sidebar (utilisateurs connectés, sauf pages auth) ===== #} {% set showSidebar = block('show_sidebar') is defined ? block('show_sidebar')|trim == 'true' : true %} {% if app.user and showSidebar %} {% set sidebarCollapsed = app.user.settings.sidebarCollapsed|default(false) %} {% set currentRoute = app.request.attributes.get('_route')|default('') %} {% set sidebarVariant = currentRoute starts with 'app_sam_' ? 'sam' : 'bubul' %} {# Sidebar - Organisme Atomic Design #} {% include "_organisms/sidebar/sidebar.html.twig" with { collapsed: sidebarCollapsed, variant: sidebarVariant } %} {# Contenu principal avec marge adaptative #}
{% endif %} {% block body %}{% endblock %} {% if app.user and showSidebar %}
{% endif %} {# ===== Système de Toast Notifications ===== #} {% include '_molecules/toast/toast.html.twig' %} {# ===== Flash Messages Symfony → Toast ===== Le format « Titre|Description » est une COMMODITÉ, jamais une condition d'affichage : un message posé sans barre verticale reste un message, et le jeter en silence est le pire des comportements — le contrôleur croit avoir parlé, l'utilisateur n'a rien vu. C'est exactement ce qui se produisait : vingt-six `addFlash()` de l'application, dont tout le parcours d'administration des commerciaux, n'atteignaient jamais l'écran. Sans barre, la phrase entière devient le titre du toast. `split('|', 2)` et non `split('|')` : une barre au milieu d'une description ne doit pas l'amputer, seule la PREMIÈRE sépare le titre du reste. #} {% for type, messages in app.flashes %} {% for message in messages %} {% set parts = message|split('|', 2) %} {% set title = parts[0]|default('')|trim %} {% set description = parts[1]|default('')|trim %} {% if title is not empty %} {% endif %} {% endfor %} {% endfor %} {# Bandeau de consentement cookies (RGPD) #} {% include '_molecules/cookie-banner/cookie-banner.html.twig' %} {# Modale de nouveauté — ne rend quelque chose que s'il y a une annonce à montrer #} {% include '_organisms/announcement-modal/announcement-modal-live.html.twig' %} {# Tutoriel interactif — ne rend quelque chose que si la page courante en a un #} {% include '_organisms/tour/tour-live.html.twig' %}