templates/blo/base.html.twig line 1

Open in your IDE?
  1. <!DOCTYPE html>
  2. <html lang="fr">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>{% block title %}BLO — Achat en ligne{% endblock %}</title>
  7.     <link rel="preconnect" href="https://fonts.googleapis.com">
  8.     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  9.     <link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800&display=swap" rel="stylesheet">
  10.     <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
  11.     <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css" rel="stylesheet">
  12.     <style>
  13.         :root {
  14.             --blo-bg: #f7f9f6;
  15.             --blo-bg-white: #ffffff;
  16.             --blo-header-bg: #ffffff;
  17.             --blo-header-search-bg: #5db85b;
  18.             --blo-header-search-hover: #4cae4c;
  19.             --blo-nav-bg: #388e3c;
  20.             --blo-text: #333333;
  21.             --blo-text-muted: #777777;
  22.             --blo-link: #388e3c;
  23.             --blo-link-hover: #2e7d32;
  24.             --blo-price: #e53935;
  25.             --blo-border: #e0e0e0;
  26.             --blo-card-bg: #fff;
  27.             --blo-bg-card: #fff;
  28.             --blo-bg-elevated: #f3f3f3;
  29.             --blo-radius: 6px;
  30.         }
  31.         * { box-sizing: border-box; }
  32.         body { font-family: 'Nunito', -apple-system, sans-serif; background: var(--blo-bg); color: var(--blo-text); min-height: 100vh; display: flex; flex-direction: column; margin: 0; }
  33.         main { flex: 1 0 auto; }
  34.         a { color: var(--blo-link); text-decoration: none; }
  35.         a:hover { color: var(--blo-link-hover); }
  36.         /* Header type Greenweez */
  37.         .blo-header-top {
  38.             background: var(--blo-header-bg);
  39.             color: var(--blo-text);
  40.             padding: 0.5rem 0;
  41.             border-bottom: 1px solid var(--blo-border);
  42.         }
  43.         .blo-header-top .container { display: flex; align-items: center; flex-wrap: wrap; gap: 0.75rem; }
  44.         .blo-logo { display: inline-flex; align-items: center; gap: 0.5rem; color: var(--blo-nav-bg) !important; font-weight: 700; font-size: 1.5rem; padding: 0.5rem 0.5rem 0.5rem 0; letter-spacing: 0.02em; }
  45.         .blo-logo:hover { color: var(--blo-link-hover) !important; opacity: 0.95; }
  46.         .blo-logo-icon { width: 36px; height: 36px; background: var(--blo-nav-bg); color: #fff; border-radius: 6px; display: flex; align-items: center; justify-content: center; font-size: 1.1rem; }
  47.         .blo-logo-text { line-height: 1; }
  48.         .blo-search-form { flex: 1; min-width: 200px; max-width: 600px; display: flex; border-radius: 50px; overflow: hidden; border: 2px solid var(--blo-header-search-bg); background: #fff;}
  49.         .blo-search-form .form-select { width: auto; min-width: 150px; border: none; border-radius: 50px 0 0 50px; background: transparent; font-size: 0.9rem; padding-right: 2rem; font-weight: 600; color: var(--blo-text-muted); }
  50.         .blo-search-form .form-select:focus { box-shadow: none; }
  51.         .blo-search-form .form-control { border: none; border-radius: 0; font-size: 0.95rem; box-shadow: none !important;}
  52.         .blo-search-form .btn-search { background: var(--blo-header-search-bg); border: none; padding: 0.5rem 1.25rem; color: #fff; border-radius: 0 50px 50px 0; font-weight: bold;}
  53.         .blo-search-form .btn-search:hover { background: var(--blo-header-search-hover); color: #fff; }
  54.         .blo-header-cart { color: var(--blo-text); display: flex; align-items: center; gap: 0.35rem; padding: 0.5rem; border-radius: var(--blo-radius); position: relative; }
  55.         .blo-header-cart:hover { color: var(--blo-link); outline: 1px solid var(--blo-border); }
  56.         .blo-header-cart i { font-size: 1.5rem; }
  57.         .blo-header-cart .blo-cart-badge { position: absolute; top: 2px; left: 50%; margin-left: 8px; min-width: 1.1rem; height: 1.1rem; padding: 0 0.25rem; font-size: 0.7rem; font-weight: 700; line-height: 1.1rem; text-align: center; background: var(--blo-header-search-bg); color: #fff; border-radius: 50%; }
  58.         .blo-header-cart .blo-cart-badge:empty { display: none; }
  59.         .blo-nav-bar { background: var(--blo-nav-bg); padding: 0.6rem 0; }
  60.         .blo-nav-bar .nav-link { color: rgba(255,255,255,0.95) !important; padding: 0.4rem 0.8rem !important; font-size: 0.95rem; font-weight: 600; transition: color 0.15s; }
  61.         .blo-nav-bar .nav-link:hover { color: #fff !important; background: rgba(255,255,255,0.1); border-radius: 20px;}
  62.         .blo-nav-bar .dropdown-menu { background: var(--blo-card-bg); border: 1px solid var(--blo-border); border-radius: var(--blo-radius); }
  63.         .blo-nav-bar .dropdown-item:hover { background: #f0f0f0; }
  64.         .blo-header-cat-btn { background: transparent !important; font-size: 0.9rem; font-weight: 600; letter-spacing: 0.01em; border-radius: var(--blo-radius); transition: background 0.15s; color: var(--blo-text) !important; }
  65.         .blo-header-cat-btn i { color: var(--blo-text); }
  66.         .blo-header-cat-btn:hover { background: rgba(0,0,0,0.05) !important; }
  67.         .blo-cat-dropdown .nav-link { background: rgba(255,255,255,0.1); border-radius: var(--blo-radius); font-weight: 600; }
  68.         .blo-cat-dropdown .nav-link:hover { background: rgba(255,255,255,0.2); }
  69.         .blo-cat-menu { min-width: 280px; padding: 0.5rem 0; max-height: 70vh; overflow-y: auto; box-shadow: 0 4px 16px rgba(0,0,0,0.15); }
  70.         .blo-cat-menu .dropdown-item { padding: 0.45rem 1rem; }
  71.         .blo-cat-menu .dropdown-item:active { background: var(--blo-header-search-bg); color: var(--blo-text); }
  72.         /* Cartes produit type Greenweez */
  73.         .blo-product-box {
  74.             background: var(--blo-card-bg);
  75.             padding: 1.5rem;
  76.             height: 100%;
  77.             border-radius: 12px;
  78.             transition: all 0.2s ease-in-out;
  79.             border: 1px solid #eaeaea;
  80.             position: relative;
  81.         }
  82.         .blo-product-box:hover { box-shadow: 0 8px 16px rgba(0,0,0,0.06); border-color: transparent; transform: translateY(-3px); }
  83.         .blo-product-box .img-wrap { aspect-ratio: 1; display: flex; align-items: center; justify-content: center; margin-bottom: 1rem; border-radius: 8px; position: relative; }
  84.         .blo-product-box .img-wrap img { max-width: 100%; max-height: 100%; object-fit: contain; }
  85.         .blo-product-box .img-wrap .bi-image { font-size: 2.5rem; opacity: 0.6; }
  86.         .blo-product-box { display: flex; flex-direction: column; }
  87.         .blo-product-box > a { display: flex !important; flex-direction: column; flex: 1; }
  88.         .blo-product-box .title { font-size: 0.95rem; line-height: 1.4; color: var(--blo-text); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; font-weight: 600; margin-bottom: 0.5rem; min-height: calc(0.95rem * 1.4 * 2); }
  89.         .blo-product-box .price { font-size: 1.15rem; font-weight: 800; color: var(--blo-text); margin: auto 0 0.5rem 0; padding-right: 60px; min-height: 40px; display: block; line-height: 1.2; white-space: normal; }
  90.         .blo-product-box .price del { display: block; font-size: 0.8rem; color: var(--blo-text-muted); font-weight: 500; margin: 0 0 2px 0; }
  91.         p.price, .blo-catalog-card .price { white-space: normal; }
  92.         
  93.         .blo-product-add-btn {
  94.             display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; 
  95.             background: var(--blo-header-search-bg); color: #fff; border-radius: 50%;
  96.             border: none; position: absolute; bottom: 1.5rem; right: 1.5rem; transition: background 0.2s;
  97.             box-shadow: 0 4px 6px rgba(93,184,91,0.25);
  98.         }
  99.         .blo-product-add-btn:hover { background: var(--blo-header-search-hover); color: #fff; transform: scale(1.05); }
  100.         .blo-section-box { background: var(--blo-card-bg); padding: 1.25rem; border-radius: var(--blo-radius); margin-bottom: 1.5rem; }
  101.         .blo-section-box h2 { font-size: 1.25rem; font-weight: 700; margin-bottom: 1rem; color: var(--blo-text); }
  102.         .blo-footer { background: var(--blo-nav-bg); color: rgba(255,255,255,0.8); padding: 2rem 0 1rem; margin-top: 2rem; flex-shrink: 0; }
  103.         .blo-footer a { color: rgba(255,255,255,0.9); }
  104.         .blo-footer a:hover { color: #fff; text-decoration: underline; }
  105.         .blo-footer h6 { color: #fff; font-size: 1rem; font-weight: 600; margin-bottom: 0.75rem; }
  106.         .blo-footer ul { list-style: none; padding: 0; margin: 0; font-size: 0.85rem; }
  107.         .blo-footer ul li { margin-bottom: 0.35rem; }
  108.         .blo-footer-bottom { background: #131a22; padding: 1rem 0; margin-top: 1rem; font-size: 0.8rem; text-align: center; }
  109.         .form-control:focus, .form-select:focus { border-color: var(--blo-header-search-bg); box-shadow: 0 0 0 2px rgba(254,189,105,0.4); }
  110.         .btn-blo-primary { background: var(--blo-header-search-bg); color: var(--blo-text); border: none; font-weight: 600; padding: 0.5rem 1rem; border-radius: var(--blo-radius); }
  111.         .btn-blo-primary:hover { background: var(--blo-header-search-hover); color: var(--blo-text); }
  112.         .breadcrumb { background: transparent; font-size: 0.85rem; }
  113.         .breadcrumb-item a { color: var(--blo-link); }
  114.         .table thead th { background: #f3f3f3; font-weight: 600; }
  115.         .pagination .page-link { color: var(--blo-text); }
  116.         .pagination .page-item.active .page-link { background: var(--blo-header-bg); border-color: var(--blo-header-bg); }
  117.         .blo-card { background: var(--blo-card-bg); border: 1px solid var(--blo-border); border-radius: var(--blo-radius); }
  118.         .btn-blo-outline { background: transparent; color: var(--blo-text); border: 1px solid var(--blo-border); border-radius: var(--blo-radius); }
  119.         .btn-blo-outline:hover { border-color: var(--blo-header-search-bg); color: var(--blo-text); background: #fff8f0; }
  120.         .blo-section-label { font-size: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--blo-text-muted); }
  121.         .blo-section-title { font-size: 1.25rem; font-weight: 700; color: var(--blo-text); }
  122.         .blo-kpi-card { background: var(--blo-card-bg); border: 1px solid var(--blo-border); border-radius: var(--blo-radius); padding: 1rem; }
  123.         .blo-kpi-card .label { font-size: 0.8rem; color: var(--blo-text-muted); }
  124.         .blo-kpi-card .value { font-weight: 700; font-size: 1.25rem; }
  125.         /* ============================================
  126.            BOUTONS MULTI-COLOR 3D (BLO)
  127.            N'affecte PAS les menus (header, navbar, dropdowns, search)
  128.            Cible uniquement les boutons dans <main> et les formulaires
  129.            ============================================ */
  130.         main .btn:not(.blo-product-add-btn):not(.btn-search),
  131.         main button.btn:not(.blo-product-add-btn):not(.btn-search),
  132.         main a.btn:not(.blo-product-add-btn):not(.btn-search),
  133.         main input.btn:not(.blo-product-add-btn):not(.btn-search),
  134.         main button[type="submit"]:not(.blo-product-add-btn):not(.btn-search),
  135.         main input[type="submit"]:not(.blo-product-add-btn):not(.btn-search),
  136.         .blo-card .btn:not(.blo-product-add-btn):not(.btn-search),
  137.         .blo-section-box .btn:not(.blo-product-add-btn):not(.btn-search),
  138.         .blo-product-box .btn:not(.blo-product-add-btn):not(.btn-search) {
  139.             background: linear-gradient(135deg, #4169E1 0%, #8B00FF 50%, #8B4513 100%) !important;
  140.             color: #FFFFFF !important;
  141.             border: none !important;
  142.             border-radius: 6px !important;
  143.             padding: 8px 18px !important;
  144.             font-weight: 600 !important;
  145.             text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3) !important;
  146.             box-shadow:
  147.                 0 4px 0 #2c3e50,
  148.                 0 6px 8px rgba(0, 0, 0, 0.3),
  149.                 inset 0 1px 0 rgba(255, 255, 255, 0.4) !important;
  150.             transition: all 0.15s ease-in-out !important;
  151.             transform: translateY(0) !important;
  152.             position: relative !important;
  153.         }
  154.         main .btn:hover,
  155.         main button.btn:hover,
  156.         main a.btn:hover,
  157.         .blo-card .btn:hover,
  158.         .blo-section-box .btn:hover,
  159.         .blo-product-box .btn:hover {
  160.             background: linear-gradient(135deg, #5a7af0 0%, #a020f0 50%, #a0522d 100%) !important;
  161.             color: #FFFFFF !important;
  162.             transform: translateY(-2px) !important;
  163.             box-shadow:
  164.                 0 6px 0 #2c3e50,
  165.                 0 10px 14px rgba(0, 0, 0, 0.35),
  166.                 inset 0 1px 0 rgba(255, 255, 255, 0.5) !important;
  167.         }
  168.         main .btn:active,
  169.         main button.btn:active,
  170.         main a.btn:active,
  171.         .blo-card .btn:active,
  172.         .blo-section-box .btn:active,
  173.         .blo-product-box .btn:active {
  174.             transform: translateY(3px) !important;
  175.             box-shadow:
  176.                 0 1px 0 #2c3e50,
  177.                 0 2px 4px rgba(0, 0, 0, 0.3),
  178.                 inset 0 1px 0 rgba(255, 255, 255, 0.3) !important;
  179.         }
  180.         /* Variantes de couleur 3D */
  181.         main .btn-success, .blo-card .btn-success {
  182.             background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%) !important;
  183.             box-shadow: 0 4px 0 #0a5d56, 0 6px 8px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.4) !important;
  184.         }
  185.         main .btn-danger, .blo-card .btn-danger {
  186.             background: linear-gradient(135deg, #ff416c 0%, #ff4b2b 100%) !important;
  187.             box-shadow: 0 4px 0 #8b1a1a, 0 6px 8px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.4) !important;
  188.         }
  189.         main .btn-warning, .blo-card .btn-warning {
  190.             background: linear-gradient(135deg, #f7971e 0%, #ffd200 100%) !important;
  191.             box-shadow: 0 4px 0 #7a4a00, 0 6px 8px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.4) !important;
  192.         }
  193.         main .btn-info, .blo-card .btn-info {
  194.             background: linear-gradient(135deg, #00c6ff 0%, #0072ff 100%) !important;
  195.             box-shadow: 0 4px 0 #003a80, 0 6px 8px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.4) !important;
  196.         }
  197.         main .btn-primary, .blo-card .btn-primary {
  198.             background: linear-gradient(135deg, #4169E1 0%, #8B00FF 100%) !important;
  199.             box-shadow: 0 4px 0 #1d2d6b, 0 6px 8px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.4) !important;
  200.         }
  201.         main .btn-secondary, .blo-card .btn-secondary {
  202.             background: linear-gradient(135deg, #654ea3 0%, #eaafc8 100%) !important;
  203.             box-shadow: 0 4px 0 #3a2a60, 0 6px 8px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.4) !important;
  204.         }
  205.         /* Sécurité : annuler tout style 3D dans les menus / header / navbar / dropdowns */
  206.         .blo-header-top .btn,
  207.         .blo-header-top button,
  208.         .blo-nav-bar .btn,
  209.         .blo-nav-bar button,
  210.         .navbar .btn,
  211.         .navbar button,
  212.         .dropdown-menu .btn,
  213.         .dropdown-menu button,
  214.         .blo-search-form .btn,
  215.         .blo-search-form button,
  216.         .blo-header-cat-btn,
  217.         .blo-product-add-btn {
  218.             background-image: none;
  219.             box-shadow: none !important;
  220.             transform: none !important;
  221.             text-shadow: none !important;
  222.         }
  223.         /* Garder le bouton rond "+" vert des produits intact */
  224.         .blo-product-add-btn {
  225.             background: var(--blo-header-search-bg) !important;
  226.             color: #fff !important;
  227.             border-radius: 50% !important;
  228.             padding: 0 !important;
  229.             position: absolute !important;
  230.             bottom: 1.5rem !important;
  231.             right: 1.5rem !important;
  232.             left: auto !important;
  233.             top: auto !important;
  234.             width: 40px !important;
  235.             height: 40px !important;
  236.             display: flex !important;
  237.             align-items: center !important;
  238.             justify-content: center !important;
  239.             border: none !important;
  240.             box-shadow: 0 4px 6px rgba(93,184,91,0.25) !important;
  241.             text-shadow: none !important;
  242.             font-weight: normal !important;
  243.         }
  244.         .blo-product-add-btn:hover {
  245.             background: var(--blo-header-search-hover) !important;
  246.         }
  247.         /* Garder le bouton de recherche vert */
  248.         .blo-search-form .btn-search {
  249.             background: var(--blo-header-search-bg) !important;
  250.             color: #fff !important;
  251.             border-radius: 0 50px 50px 0 !important;
  252.         }
  253.         .blo-search-form .btn-search:hover {
  254.             background: var(--blo-header-search-hover) !important;
  255.         }
  256.         /* ============================================
  257.            FOOTER MULTI-COLOR 3D (BLO)
  258.            ============================================ */
  259.         .blo-footer {
  260.             background: linear-gradient(135deg, #4169E1 0%, #8B00FF 25%, #ff416c 50%, #f7971e 75%, #11998e 100%) !important;
  261.             background-size: 200% 200% !important;
  262.             animation: bloFooterGradient 8s ease infinite !important;
  263.             color: #FFFFFF !important;
  264.             text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5) !important;
  265.             border-top: 3px solid rgba(255, 255, 255, 0.3) !important;
  266.             box-shadow:
  267.                 0 -4px 0 rgba(0, 0, 0, 0.3),
  268.                 0 -8px 20px rgba(0, 0, 0, 0.4),
  269.                 inset 0 2px 0 rgba(255, 255, 255, 0.4),
  270.                 inset 0 -2px 0 rgba(0, 0, 0, 0.3) !important;
  271.             letter-spacing: 0.5px !important;
  272.         }
  273.         .blo-footer h6,
  274.         .blo-footer a,
  275.         .blo-footer ul li,
  276.         .blo-footer p,
  277.         .blo-footer span {
  278.             color: #FFFFFF !important;
  279.             text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5) !important;
  280.         }
  281.         .blo-footer-bottom {
  282.             background: rgba(0, 0, 0, 0.35) !important;
  283.             color: #FFFFFF !important;
  284.             text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5) !important;
  285.         }
  286.         @keyframes bloFooterGradient {
  287.             0%   { background-position: 0% 50%; }
  288.             50%  { background-position: 100% 50%; }
  289.             100% { background-position: 0% 50%; }
  290.         }
  291.     </style>
  292.     {% block stylesheets %}{% endblock %}
  293. </head>
  294. <body>
  295.     <header class="blo-header-top">
  296.         <div class="container">
  297.             <a class="blo-logo" href="{{ path('app_blo_home_index') }}" aria-label="BLO Accueil">
  298.                 {% set site_logo = blo_logo() %}
  299.                 {% if site_logo %}
  300.                     <img src="{{ site_logo }}" alt="BLO" style="max-height: 60px; max-width: 250px; object-fit: contain;">
  301.                 {% else %}
  302.                     <span class="blo-logo-icon"><i class="bi bi-bag-heart-fill"></i></span>
  303.                     <span class="blo-logo-text">BLO</span>
  304.                 {% endif %}
  305.             </a>
  306.             <div class="dropdown d-none d-md-inline-block">
  307.                 <button class="btn btn-sm text-white border-0 dropdown-toggle py-1 px-2 blo-header-cat-btn" type="button" data-bs-toggle="dropdown" aria-expanded="false">
  308.                     <i class="bi bi-list" style="font-size: 1.2rem;"></i>
  309.                 </button>
  310.                 <ul class="dropdown-menu blo-cat-menu">
  311.                     <li><a class="dropdown-item fw-semibold" href="{{ path('blo_catalog') }}"><i class="bi bi-grid me-2"></i>Toutes les catégories</a></li>
  312.                     {% set headerCats = blo_nav_categories() %}
  313.                     {% if headerCats|length > 0 %}
  314.                     <li><hr class="dropdown-divider my-1"></li>
  315.                     {% for cat in headerCats %}
  316.                     <li>
  317.                         <a class="dropdown-item d-flex align-items-center" href="{{ path('blo_catalog', { category: cat.id }) }}">
  318.                             <strong>{{ cat.name }}</strong>
  319.                         </a>
  320.                     </li>
  321.                     {% if cat.children|length > 0 %}
  322.                     {% for sub in cat.children %}
  323.                     <li>
  324.                         <a class="dropdown-item text-muted" href="{{ path('blo_catalog', { category: sub.id }) }}" style="font-size: 0.85rem; padding-left: 2rem;">
  325.                             {{ sub.name }}
  326.                         </a>
  327.                     </li>
  328.                     {% endfor %}
  329.                     {% endif %}
  330.                     {% endfor %}
  331.                     {% endif %}
  332.                 </ul>
  333.             </div>
  334.             <form action="{{ path('blo_catalog') }}" method="get" class="blo-search-form">
  335.                 <select name="category" class="form-select" aria-label="Catégorie">
  336.                     <option value="" {{ app.request.query.get('category') == '' ? 'selected' }}>Toutes catégories</option>
  337.                     {% for cat in blo_nav_categories() %}
  338.                     <option value="{{ cat.id }}" {{ app.request.query.getInt('category') == cat.id ? 'selected' }}>{{ cat.name }}</option>
  339.                     {% endfor %}
  340.                 </select>
  341.                 <input type="search" name="q" class="form-control" placeholder="Rechercher sur BLO" value="{{ app.request.query.get('q', '') }}" aria-label="Recherche">
  342.                 <button type="submit" class="btn btn-search"><i class="bi bi-search"></i></button>
  343.             </form>
  344.             <div class="dropdown d-none d-md-inline-block">
  345.                 <button class="btn btn-sm border-0 dropdown-toggle py-1 px-2" type="button" data-bs-toggle="dropdown" aria-expanded="false" style="background: transparent; font-size: 0.85rem; color: var(--blo-text);">
  346.                     <i class="bi bi-currency-exchange me-1"></i>{{ blo_currency_label(blo_current_currency) }}
  347.                 </button>
  348.                 <ul class="dropdown-menu dropdown-menu-end" style="min-width: 220px;">
  349.                     <li class="px-3 py-1"><small class="text-muted fw-semibold">Choisir une devise</small></li>
  350.                     <li><hr class="dropdown-divider my-1"></li>
  351.                     {% for code, label in blo_currencies %}
  352.                     <li>
  353.                         <form action="{{ path('blo_currency_switch') }}" method="post" class="d-inline w-100">
  354.                             <input type="hidden" name="currency" value="{{ code }}">
  355.                             <button type="submit" class="dropdown-item d-flex justify-content-between align-items-center{{ blo_current_currency == code ? ' active' : '' }}">
  356.                                 <span>{{ blo_currency_label(code) }} <small class="text-muted">— {{ label }}</small></span>
  357.                                 {% if blo_current_currency == code %}<i class="bi bi-check-lg"></i>{% endif %}
  358.                             </button>
  359.                         </form>
  360.                     </li>
  361.                     {% endfor %}
  362.                 </ul>
  363.             </div>
  364.             {% set cart_count = blo_cart_count() %}
  365.             <a href="{{ path('blo_cart') }}" class="blo-header-cart" aria-label="Panier ({{ cart_count }} article{{ cart_count > 1 ? 's' : '' }})">
  366.                 <span class="position-relative">
  367.                     <i class="bi bi-cart3"></i>
  368.                     {% if cart_count > 0 %}
  369.                     <span class="blo-cart-badge">{{ cart_count > 99 ? '99+' : cart_count }}</span>
  370.                     {% endif %}
  371.                 </span>
  372.                 <span class="d-none d-md-inline">Panier{% if cart_count > 0 %} ({{ cart_count }}){% endif %}</span>
  373.             </a>
  374.         </div>
  375.     </header>
  376.     <nav class="navbar navbar-expand-lg navbar-dark blo-nav-bar py-0">
  377.         <div class="container">
  378.             <button class="navbar-toggler border-light" type="button" data-bs-toggle="collapse" data-bs-target="#bloNav" aria-label="Menu"><span class="navbar-toggler-icon"></span></button>
  379.             <div class="collapse navbar-collapse" id="bloNav">
  380.                 <ul class="navbar-nav me-auto">
  381.                     <li class="nav-item"><a class="nav-link" href="{{ path('app_blo_home_index') }}">Accueil</a></li>
  382.                     <li class="nav-item"><a class="nav-link" href="{{ path('blo_catalog') }}">Catalogue</a></li>
  383.                     <li class="nav-item dropdown blo-cat-dropdown">
  384.                         <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false"><i class="bi bi-grid-fill me-1"></i>Toutes les catégories</a>
  385.                         <ul class="dropdown-menu blo-cat-menu">
  386.                             <li><a class="dropdown-item fw-semibold" href="{{ path('blo_catalog') }}"><i class="bi bi-grid me-2"></i>Toutes les catégories</a></li>
  387.                             {% set navCats = blo_nav_categories() %}
  388.                             {% if navCats|length > 0 %}
  389.                             <li><hr class="dropdown-divider my-1"></li>
  390.                             {% for cat in navCats %}
  391.                             <li>
  392.                                 <a class="dropdown-item d-flex align-items-center" href="{{ path('blo_catalog', { category: cat.id }) }}">
  393.                                     <i class="bi bi-chevron-right me-2 text-muted" style="font-size: 0.7rem;"></i>
  394.                                     <strong>{{ cat.name }}</strong>
  395.                                 </a>
  396.                             </li>
  397.                             {% if cat.children|length > 0 %}
  398.                             {% for sub in cat.children %}
  399.                             <li>
  400.                                 <a class="dropdown-item ps-5 text-muted" href="{{ path('blo_catalog', { category: sub.id }) }}" style="font-size: 0.85rem;">
  401.                                     {{ sub.name }}
  402.                                 </a>
  403.                             </li>
  404.                             {% endfor %}
  405.                             {% endif %}
  406.                             {% endfor %}
  407.                             {% endif %}
  408.                         </ul>
  409.                     </li>
  410.                     <li class="nav-item"><a class="nav-link" href="{{ path('blo_catalog') }}?promo=1">Promotions</a></li>
  411.                     <li class="nav-item"><a class="nav-link" href="{{ path('blo_catalog') }}?newest=1">Nouveautés</a></li>
  412.                     {% if is_granted('ROLE_ADMIN') %}
  413.                     <li class="nav-item"><a class="nav-link" href="{{ path('blo_admin_dashboard') }}">Admin</a></li>
  414.                     {% endif %}
  415.                     <li class="nav-item"><a class="nav-link" href="{{ path('blo_contact') }}">Contact</a></li>
  416.                     <li class="nav-item"><a class="nav-link" href="{{ path('blo_faq') }}">FAQ</a></li>
  417.                 </ul>
  418.                 <ul class="navbar-nav">
  419.                     <li class="nav-item dropdown d-md-none">
  420.                         <a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown"><i class="bi bi-currency-exchange me-1"></i>{{ blo_currency_label(blo_current_currency) }}</a>
  421.                         <ul class="dropdown-menu">
  422.                             {% for code, label in blo_currencies %}
  423.                             <li>
  424.                                 <form action="{{ path('blo_currency_switch') }}" method="post" class="d-inline w-100">
  425.                                     <input type="hidden" name="currency" value="{{ code }}">
  426.                                     <button type="submit" class="dropdown-item{{ blo_current_currency == code ? ' active' : '' }}">{{ blo_currency_label(code) }} — {{ label }}</button>
  427.                                 </form>
  428.                             </li>
  429.                             {% endfor %}
  430.                         </ul>
  431.                     </li>
  432.                     {% if app.user %}
  433.                     <li class="nav-item dropdown">
  434.                         {% set displayName = (app.user.prenom|default('') ~ ' ' ~ app.user.name|default(''))|trim %}
  435.                         {% if displayName == '' %}{% set displayName = app.user.userIdentifier %}{% endif %}
  436.                         <a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown">{{ displayName }}</a>
  437.                         <ul class="dropdown-menu dropdown-menu-end">
  438.                             <li><a class="dropdown-item" href="{{ path('blo_orders') }}">Mes commandes</a></li>
  439.                             <li><a class="dropdown-item" href="{{ path('blo_account_change_password') }}"><i class="bi bi-key me-2"></i>Changer mon mot de passe</a></li>
  440.                             <li><hr class="dropdown-divider"></li>
  441.                             <li><a class="dropdown-item" href="{{ path('app_logout') }}">Déconnexion</a></li>
  442.                         </ul>
  443.                     </li>
  444.                     {% else %}
  445.                     <li class="nav-item"><a class="nav-link" href="{{ path('login') }}">Connexion</a></li>
  446.                     <li class="nav-item"><a class="nav-link" href="{{ path('blo_register') }}">Inscription</a></li>
  447.                     {% endif %}
  448.                 </ul>
  449.             </div>
  450.         </div>
  451.     </nav>
  452.     <main class="py-3">
  453.         {% for type, messages in app.flashes %}
  454.             {% for msg in messages %}
  455.             <div class="container mb-2">
  456.                 <div class="alert alert-{{ type == 'error' ? 'danger' : type }} alert-dismissible fade show py-2" role="alert">
  457.                     {{ msg }}
  458.                     <button type="button" class="btn-close btn-close-sm" data-bs-dismiss="alert"></button>
  459.                 </div>
  460.             </div>
  461.             {% endfor %}
  462.         {% endfor %}
  463.         {% block body %}{% endblock %}
  464.     </main>
  465.     <footer class="blo-footer">
  466.         <div class="container">
  467.             <div class="row g-4">
  468.                 <div class="col-6 col-md-3">
  469.                     <h6>À propos</h6>
  470.                     <ul>
  471.                         <li><a href="{{ path('blo_contact') }}">Contact</a></li>
  472.                         <li><a href="{{ path('blo_faq') }}">FAQ</a></li>
  473.                         <li><a href="{{ path('blo_cgu') }}">CGU</a></li>
  474.                         <li><a href="{{ path('blo_confidentialite') }}">Confidentialité</a></li>
  475.                     </ul>
  476.                 </div>
  477.                 <div class="col-6 col-md-3">
  478.                     <h6>Compte</h6>
  479.                     <ul>
  480.                         <li><a href="{{ path('blo_orders') }}">Mes commandes</a></li>
  481.                         <li><a href="{{ path('blo_cart') }}">Panier</a></li>
  482.                         {% if not app.user %}<li><a href="{{ path('login') }}">Connexion</a></li>{% endif %}
  483.                     </ul>
  484.                 </div>
  485.                 <div class="col-6 col-md-3">
  486.                     <h6>Langue & devise</h6>
  487.                     <p class="small mb-2">Français · {{ blo_currency_label(blo_current_currency) }}</p>
  488.                     <form action="{{ path('blo_currency_switch') }}" method="post">
  489.                         <select name="currency" class="form-select form-select-sm bg-dark text-white border-secondary" style="max-width: 180px; font-size: 0.8rem;" onchange="this.form.submit()">
  490.                             {% for code, label in blo_currencies %}
  491.                             <option value="{{ code }}" {{ blo_current_currency == code ? 'selected' : '' }}>{{ blo_currency_label(code) }} — {{ label }}</option>
  492.                             {% endfor %}
  493.                         </select>
  494.                     </form>
  495.                 </div>
  496.             </div>
  497.             <div class="blo-footer-bottom">
  498.                 &copy; {{ 'now'|date('Y') }} GLOBAL BUSINESS AFRICA. Tous droits réservés.
  499.             </div>
  500.         </div>
  501.     </footer>
  502.     <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
  503.     {% block javascripts %}{% endblock %}
  504.     <!-- WhatsApp Chatbox Widget -->
  505.     <div style="position:fixed;bottom:24px;right:24px;z-index:999999;font-family:Segoe UI,sans-serif;">
  506.         <!-- Popup -->
  507.         <div id="wachat-popup" style="display:none;position:absolute;bottom:75px;right:0;width:320px;border-radius:16px;overflow:hidden;box-shadow:0 8px 30px rgba(0,0,0,0.25);">
  508.             <div style="background:#075E54;padding:14px 16px;display:flex;align-items:center;gap:12px;">
  509.                 <div style="width:44px;height:44px;background:#25D366;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;">
  510.                     <svg viewBox="0 0 24 24" style="width:26px;height:26px;fill:white;"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>
  511.                 </div>
  512.                 <div style="flex:1;">
  513.                     <strong style="display:block;font-size:15px;color:white;">DONDONROU</strong>
  514.                     <span style="font-size:12px;color:#b2dfdb;">&#x25cf; En ligne</span>
  515.                 </div>
  516.                 <span onclick="document.getElementById('wachat-popup').style.display='none'" style="cursor:pointer;font-size:22px;color:rgba(255,255,255,0.8);line-height:1;">&times;</span>
  517.             </div>
  518.             <div style="background:#ECE5DD;padding:16px;">
  519.                 <div style="background:white;border-radius:0 10px 10px 10px;padding:10px 14px;font-size:13.5px;color:#333;line-height:1.5;box-shadow:0 1px 3px rgba(0,0,0,0.1);">
  520.                     Bonjour !<br>Comment pouvons-nous vous aider ? Envoyez-nous un message sur WhatsApp.
  521.                 </div>
  522.                 <div style="text-align:right;font-size:11px;color:#888;margin-top:4px;">Maintenant</div>
  523.                 <a href="https://wa.me/22378614333?text=Bonjour%2C%20je%20souhaite%20avoir%20plus%20d%27informations."
  524.                    target="_blank" rel="noopener noreferrer"
  525.                    style="display:block;margin-top:14px;background:#25D366;color:white;text-align:center;padding:10px;border-radius:8px;font-size:14px;font-weight:600;text-decoration:none;">
  526.                     Demarrer la conversation
  527.                 </a>
  528.             </div>
  529.         </div>
  530.         <!-- Bouton flottant -->
  531.         <div onclick="var p=document.getElementById('wachat-popup');var b=document.getElementById('wachat-badge');if(p.style.display==='block'){p.style.display='none'}else{p.style.display='block';if(b)b.style.display='none'}"
  532.              style="position:relative;width:60px;height:60px;background:#25D366;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 12px rgba(37,211,102,0.5);">
  533.             <div id="wachat-badge" style="position:absolute;top:-4px;right:-4px;background:#ff3b30;color:white;font-size:11px;font-weight:bold;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center;">1</div>
  534.             <svg viewBox="0 0 24 24" style="width:34px;height:34px;fill:white;"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>
  535.         </div>
  536.     </div>
  537. </body>
  538. </html>