{# ========================================================= FOOTER WhileResume — thème Sociala (v4 — routes vérifiées) Colonnes : 1. Mon compte / Commencer ici (stores + liens action) 2. Articles récents (featured ArticlesRepository::getLast) 3. Emplois par ville (JobsFilters type=city) 4. Entreprises par ville (EnterprisesFilters type=city) 5. Pages SEO (LandingJobs featured) ⚠️ Routes utilisées (vérifiées contre routes.yml) : ✓ whileresume_homepage / locale_whileresume_homepage ✓ cvs_website_article / locale_cvs_website_article ✓ cvs_application_jobs_filter / locale_cvs_application_jobs_filter ✓ cvs_application_companies_filter / locale_cvs_application_companies_filter ✓ cvs_application_job_new / locale_cvs_application_job_new (= /post-a-job) ✓ whileresume_jobs_list / locale_whileresume_jobs_list ✓ whileresume_companies_list / locale_whileresume_companies_list ✓ app_logout ⚠️ À CONFIRMER (pas dans routes.yml uploadé — sans doute dans whileresume_resume/whileresume_business) : - app_login / locale_app_login → bouton login - cvs_gestion_candidates_register / locale_… → inscription candidat - cvs_gestion_enterprises_register / locale_… → inscription pro - cvs_application_cv_builder / locale_… → créateur de CV - cvs_gestion_candidates_profile_profile → profil candidat connecté - cvs_gestion_enterprises_profile_profile → profil entreprise connecté - cvs_gestion_enterprises_settings → settings entreprise - cvs_application_landing_jobs_show → page d'une LandingJobs (slug) 👉 Si une route n'existe pas, remplace-la directement dans ce fichier (un seul endroit à modifier par lien). ========================================================= #}{% set _locale = app.request.locale %}{% set _isFr = _locale == 'fr' %}{# Données dynamiques #}{% set footerArticles = getFooterArticles(_locale, 5) %}{% set footerLandingJobs = getFooterFeaturedLandingJobs(_locale, 5) %}{% set footerJobsCities = getFooterJobsCities(_locale, 6) %}{% set footerEnterprisesCities = getFooterEnterprisesCities(_locale, 6) %}<style> /* ---------- Footer WhileResume ---------- */ .whr-footer { margin-top: 32px; padding: 36px 24px 24px; background: #F9FAFD; border-radius: 16px; color: #2c2c46; } .theme-dark .whr-footer { background: #2a2a3c; color: #e9e9ef; } /* Stores en haut de la col 1 */ .whr-footer .whr-stores { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; } .whr-footer .whr-store-link { display: inline-flex; align-items: center; gap: 10px; padding: 8px 14px; background: #111; color: #fff !important; border-radius: 10px; font-size: 12px; font-weight: 600; text-decoration: none !important; line-height: 1.2; transition: transform .15s ease, background .2s ease; max-width: 170px; } .whr-footer .whr-store-link:hover { background: #2c2c46; transform: translateY(-1px); } .whr-footer .whr-store-link small { display: block; font-weight: 400; font-size: 10px; opacity: .7; } .whr-footer .whr-store-link strong { font-size: 13px; display: block; } /* Colonnes */ .whr-footer .whr-foot-col h4 { font-size: 13px; font-weight: 700; margin: 0 0 14px 0; color: inherit; text-transform: uppercase; letter-spacing: .3px; } .whr-footer .whr-foot-col ul { list-style: none; padding: 0; margin: 0; font-size: 13px; } .whr-footer .whr-foot-col ul li { margin-bottom: 10px; } .whr-footer .whr-foot-col a { color: inherit; opacity: .75; text-decoration: none; transition: opacity .2s ease, color .2s ease; } .whr-footer .whr-foot-col a:hover { opacity: 1; color: var(--theme-color, #6C3AED); } .whr-footer .whr-foot-empty { font-size: 12px; opacity: .5; font-style: italic; } /* Liste avec icônes (col 1) */ .whr-footer .whr-foot-action-links a { display: inline-flex; align-items: center; gap: 8px; } .whr-footer .whr-foot-action-links a i { font-size: 14px; opacity: .7; width: 16px; text-align: center; } /* Mini-icône ville pour cols 3 et 4 */ .whr-footer .whr-foot-col .whr-city-link { display: inline-flex; align-items: center; gap: 6px; } .whr-footer .whr-foot-col .whr-city-link .whr-city-icon { font-size: 14px; line-height: 1; display: inline-block; width: 18px; text-align: center; opacity: .85; } /* Grille principale : 1 col → 2 cols → 5 cols */ .whr-footer .whr-foot-grid { display: grid; gap: 28px; grid-template-columns: 1fr; } @media (min-width: 576px) { .whr-footer .whr-foot-grid { grid-template-columns: 1fr 1fr; } } @media (min-width: 992px) { .whr-footer .whr-foot-grid { grid-template-columns: repeat(5, 1fr); gap: 32px; } } /* Bottom bar */ .whr-footer .whr-foot-bottom { margin-top: 32px; padding-top: 20px; border-top: 1px solid rgba(0,0,0,.08); display: flex; flex-direction: column; gap: 14px; align-items: center; text-align: center; } .theme-dark .whr-footer .whr-foot-bottom { border-top-color: rgba(255,255,255,.1); } @media (min-width: 768px) { .whr-footer .whr-foot-bottom { flex-direction: row; justify-content: space-between; text-align: left; } } .whr-footer .whr-foot-copy { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; opacity: .7; margin: 0; } .whr-footer .whr-foot-copy img.whr-favicon { width: 18px; height: 18px; border-radius: 4px; flex-shrink: 0; } .whr-footer .whr-foot-legal { display: flex; flex-wrap: wrap; gap: 6px 16px; justify-content: center; font-size: 12px; } .whr-footer .whr-foot-legal a { color: inherit; opacity: .75; text-decoration: none; } .whr-footer .whr-foot-legal a:hover { opacity: 1; } .whr-footer .whr-foot-legal .whr-admin-link { color: #e74c3c !important; opacity: 1; } .whr-footer .whr-foot-social { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; padding: 0; margin: 0; } .whr-footer .whr-foot-social a { width: 32px; height: 32px; border-radius: 8px; background: #fff; display: inline-flex; align-items: center; justify-content: center; color: #2c2c46; text-decoration: none !important; transition: background .2s ease, color .2s ease, transform .15s ease; box-shadow: 0 1px 2px rgba(0,0,0,.04); } .whr-footer .whr-foot-social a:hover { background: var(--theme-color, #6C3AED); color: #fff; transform: translateY(-1px); } .theme-dark .whr-footer .whr-foot-social a { background: #34344a; color: #fff; box-shadow: none; } .whr-footer .whr-foot-social i { font-size: 14px; } .middle-sidebar-left .whr-footer { width: 100%; } @media (max-width: 575.98px) { .whr-footer { padding: 24px 18px 20px; } }</style><footer class="whr-footer" role="contentinfo"> {# === Grille principale 5 colonnes === #} <div class="whr-foot-grid"> {# ===== Col 1 : Mon compte / Commencer ici ===== #} {% if _isFr %} {% set _ios = ios_fr %} {% set _android = android_fr %} {% else %} {% set _ios = ios_us %} {% set _android = android_us %} {% endif %} <div class="whr-foot-col whr-foot-col-action"> {% if connectUser %} <h4>{{ 'layout.footer.my_account'|trans({}, 'whr-public')|default('Mon compte') }}</h4> {% else %} <h4>{{ 'layout.footer.start_here'|trans({}, 'whr-public')|default('Commencer ici') }}</h4> {% endif %} <div class="whr-stores"> {% if _ios %} <a href="{{ _ios }}" class="whr-store-link" target="_blank" rel="noopener" aria-label="App Store"> <svg width="18" height="18" viewBox="0 0 24 24" fill="#fff" aria-hidden="true"> <path d="M18.71 19.5C17.88 20.74 17 21.95 15.66 21.97C14.32 22 13.89 21.18 12.37 21.18C10.84 21.18 10.37 21.95 9.09997 22C7.78997 22.05 6.79997 20.68 5.95997 19.47C4.24997 17 2.93997 12.45 4.69997 9.39C5.56997 7.87 7.12997 6.91 8.81997 6.88C10.1 6.86 11.32 7.75 12.11 7.75C12.89 7.75 14.37 6.68 15.92 6.84C16.57 6.87 18.39 7.1 19.56 8.82C19.47 8.88 17.39 10.1 17.41 12.63C17.44 15.65 20.06 16.66 20.09 16.67C20.06 16.74 19.67 18.11 18.71 19.5ZM13 3.5C13.73 2.67 14.94 2.04 15.94 2C16.07 3.17 15.6 4.35 14.9 5.19C14.21 6.04 13.07 6.7 11.95 6.61C11.8 5.46 12.36 4.26 13 3.5Z"/> </svg> <span> <small>{{ 'layout.download_on'|trans({}, 'whr-public')|default('Télécharger sur') }}</small> <strong>App Store</strong> </span> </a> {% endif %} {% if _android %} <a href="{{ _android }}" class="whr-store-link" target="_blank" rel="noopener" aria-label="Google Play"> <svg width="18" height="18" viewBox="0 0 512 512" aria-hidden="true"> <path style="fill:#3A9BC8;" d="M225.656,256.052L14.016,485.451l-6.442,7.052c-4.005-5.919-6.704-12.972-7.313-20.806C0.087,470.305,0,468.91,0,467.518V44.499c0-9.488,2.873-18.02,7.574-24.987L225.656,256.052z"/> <path style="fill:#9BCD83;" d="M320.811,152.8l-95.155,103.253L7.574,19.512C19.936,1.405,45.183-6.342,66.6,6.02L320.811,152.8z"/> <path style="fill:#EEB84C;" d="M455.056,257.27c-0.348,14.453-7.748,28.904-22.113,37.174l-112.132,64.771l-95.155-103.163L320.811,152.8l70.518,40.745l41.614,24.026C448.178,226.366,455.579,241.861,455.056,257.27z"/> <path style="fill:#B43F70;" d="M7.591,492.492c12.368,18.116,37.599,25.838,58.976,13.496L320.775,359.22l-95.156-103.209L7.591,492.492z"/> </svg> <span> <small>{{ 'layout.available_on'|trans({}, 'whr-public')|default('Disponible sur') }}</small> <strong>Google Play</strong> </span> </a> {% endif %} </div> <ul class="whr-foot-action-links"> {% if connectUser %} {% if isCandidateUser %} <li> <a href="{% if _isFr %}{{ path('locale_cvs_gestion_candidates_profile_profile', {'_locale': _locale}) }}{% else %}{{ path('cvs_gestion_candidates_profile_profile') }}{% endif %}"> <i class="feather-user"></i> {{ 'layout.footer.my_profile'|trans({}, 'whr-public')|default('Mon profil') }} </a> </li> {% else %} <li> <a href="{% if _isFr %}{{ path('locale_cvs_gestion_enterprises_profile_profile', {'_locale': _locale}) }}{% else %}{{ path('cvs_gestion_enterprises_profile_profile') }}{% endif %}"> <i class="feather-user"></i> {{ 'layout.footer.my_profile'|trans({}, 'whr-public')|default('Mon profil') }} </a> </li> <li> <a href="{% if _isFr %}{{ path('locale_cvs_gestion_enterprises_settings', {'_locale': _locale}) }}{% else %}{{ path('cvs_gestion_enterprises_settings') }}{% endif %}"> <i class="feather-settings"></i> {{ 'layout.footer.settings'|trans({}, 'whr-public')|default('Paramètres') }} </a> </li> {% endif %} <li> <a href="{{ path('app_logout') }}"> <i class="feather-log-out"></i> {{ 'layout.footer.logout'|trans({}, 'whr-public')|default('Déconnexion') }} </a> </li> {% else %} {# Pas connecté : on pousse vers les CTA principaux du site #} <li> <a href="{% if _isFr %}{{ path('locale_whileresume_jobs_list', {'_locale': _locale}) }}{% else %}{{ path('whileresume_jobs_list') }}{% endif %}"> <i class="feather-briefcase"></i> {{ 'layout.footer.browse_jobs'|trans({}, 'whr-public')|default('Voir les offres') }} </a> </li> <li> <a href="{% if _isFr %}{{ path('locale_whileresume_companies_list', {'_locale': _locale}) }}{% else %}{{ path('whileresume_companies_list') }}{% endif %}"> <i class="feather-grid"></i> {{ 'layout.footer.browse_companies'|trans({}, 'whr-public')|default('Voir les entreprises') }} </a> </li> <li> <a href="{% if _isFr %}{{ path('locale_cvs_application_job_new', {'_locale': _locale}) }}{% else %}{{ path('cvs_application_job_new') }}{% endif %}"> <i class="feather-plus-circle"></i> {{ 'layout.footer.post_job'|trans({}, 'whr-public')|default('Publier une offre') }} </a> </li> {% endif %} </ul> </div> {# ===== Col 2 : Articles récents (featured) ===== #} <div class="whr-foot-col"> <h4>{{ 'layout.footer.latest_articles'|trans({}, 'whr-public')|default('Articles récents') }}</h4> {% if footerArticles is not empty %} <ul> {% for article in footerArticles %} <li> <a href="{% if _isFr %}{{ path('locale_cvs_website_article', {'_locale': _locale, 'slug': article.slug}) }}{% else %}{{ path('cvs_website_article', {'slug': article.slug}) }}{% endif %}" title="{{ article.title }}"> {{ article.shortTitle ?: cleanSubstr(article.title, 45) }} </a> </li> {% endfor %} </ul> {% else %} <p class="whr-foot-empty">{{ 'layout.footer.coming_soon'|trans({}, 'whr-public')|default('Bientôt disponible') }}</p> {% endif %} </div> {# ===== Col 3 : Emplois par ville ===== #} <div class="whr-foot-col"> <h4>{{ 'layout.footer.jobs_by_city'|trans({}, 'whr-public')|default('Emplois par ville') }}</h4> {% if footerJobsCities is not empty %} <ul> {% for city in footerJobsCities %} <li> <a class="whr-city-link" href="{% if _isFr %}{{ path('locale_cvs_application_jobs_filter', {'_locale': _locale, 'slug': city.slug}) }}{% else %}{{ path('cvs_application_jobs_filter', {'slug': city.slug}) }}{% endif %}" title="{{ city.shortTitle ?: city.label }}"> {% if city.icon %} <span class="whr-city-icon">{{ city.icon }}</span> {% else %} <i class="feather-map-pin whr-city-icon"></i> {% endif %} <span>{{ city.label }}</span> </a> </li> {% endfor %} </ul> {% else %} <p class="whr-foot-empty">{{ 'layout.footer.coming_soon'|trans({}, 'whr-public')|default('Bientôt disponible') }}</p> {% endif %} </div> {# ===== Col 4 : Entreprises par ville ===== #} <div class="whr-foot-col"> <h4>{{ 'layout.footer.companies_by_city'|trans({}, 'whr-public')|default('Entreprises par ville') }}</h4> {% if footerEnterprisesCities is not empty %} <ul> {% for city in footerEnterprisesCities %} <li> <a class="whr-city-link" href="{% if _isFr %}{{ path('locale_cvs_application_companies_filter', {'_locale': _locale, 'slug': city.slug}) }}{% else %}{{ path('cvs_application_companies_filter', {'slug': city.slug}) }}{% endif %}" title="{{ city.shortTitle ?: city.label }}"> {% if city.icon %} <span class="whr-city-icon">{{ city.icon }}</span> {% else %} <i class="feather-map-pin whr-city-icon"></i> {% endif %} <span>{{ city.label }}</span> </a> </li> {% endfor %} </ul> {% else %} <p class="whr-foot-empty">{{ 'layout.footer.coming_soon'|trans({}, 'whr-public')|default('Bientôt disponible') }}</p> {% endif %} </div> {# ===== Col 5 : Pages SEO (LandingJobs featured) ===== ⚠️ Route 'cvs_application_landing_jobs_show' non trouvée dans tes routes.yml (peut-être dans whileresume_resume.yml ?). Adapte si besoin. #} <div class="whr-foot-col"> <h4>{{ 'layout.footer.featured_pages'|trans({}, 'whr-public')|default('À découvrir') }}</h4> {% if footerLandingJobs is not empty %} <ul> {% for landing in footerLandingJobs %} <li> <a href="{% if _isFr %}{{ path('locale_whileresume_homepage_landing', {'_locale': _locale, 'slug': landing.slug}) }}{% else %}{{ path('whileresume_homepage_landing', {'slug': landing.slug}) }}{% endif %}"> {{ landing.title }} </a> </li> {% endfor %} </ul> {% endif %} </div> </div> {# === Bas du footer === #} <div class="whr-foot-bottom"> <p class="whr-foot-copy"> {% if favicon %} <img src="{{ favicon }}" alt="" class="whr-favicon" /> {% endif %} <span>© {{ "now"|date('Y') }} {{ websitename }}. {{ 'layout.rights_reserved'|trans({}, 'whr-public')|default('Tous droits réservés.') }}</span> </p> <div class="whr-foot-legal"> {% set menuFooter = getMenuWebsiteLocaleArray(_locale, "footer", connectUser) %} {% if menuFooter is not empty %} {% for m in menuFooter %} <a href="{{ m.link }}" aria-label="{{ m.title }}" title="{{ m.title }}" {% if m.targetBlank == 1 %}target="_blank" rel="noreferrer"{% endif %}> {{ m.title }} </a> {% endfor %} {% endif %} {% if app.user is not null and is_granted("ROLE_SUPER_ADMIN") %} <a href="{{ path('backoffice_dashboard') }}" class="whr-admin-link" title="Administration"> <i class="feather-settings"></i> Administration </a> {% endif %} </div> <ul class="whr-foot-social"> {% if facebook %} <li><a href="{{ facebook }}" target="_blank" rel="noopener" aria-label="Facebook"><i class="feather-facebook"></i></a></li> {% endif %} {% if twitter %} <li><a href="{{ twitter }}" target="_blank" rel="noopener" aria-label="X / Twitter"><i class="feather-twitter"></i></a></li> {% endif %} {% if instagram %} <li><a href="{{ instagram }}" target="_blank" rel="noopener" aria-label="Instagram"><i class="feather-instagram"></i></a></li> {% endif %} {% if linkedin %} <li><a href="{{ linkedin }}" target="_blank" rel="noopener" aria-label="LinkedIn"><i class="feather-linkedin"></i></a></li> {% endif %} {% if youtube %} <li><a href="{{ youtube }}" target="_blank" rel="noopener" aria-label="YouTube"><i class="feather-youtube"></i></a></li> {% endif %} </ul> </div></footer>