templates/components/_header.html.twig line 1

Open in your IDE?
  1. {% set route = app.request.attributes.get('_route') %}
  2. <header class="bg-white shadow-lg sticky top-0 z-50 border-b border-gray-100">
  3. <div class="container mx-auto px-4 md:px-6">
  4. <!-- Top bar — desktop uniquement -->
  5. <div class="bg-gray-50 border-b border-gray-100 hidden lg:block">
  6. <div class="container mx-auto px-4 md:px-6 py-2">
  7. <div class="flex justify-between items-center text-sm">
  8. <!-- Infos contact -->
  9. <div class="flex items-center space-x-6 text-gray-600">
  10. <span>
  11. <i class="fas fa-phone-alt mr-2 text-[#006633]"></i>
  12. +269 123 45 67
  13. </span>
  14. <span>
  15. <i class="fas fa-envelope mr-2 text-[#006633]"></i>
  16. contact@journal-officiel.km
  17. </span>
  18. <span>
  19. <i class="fas fa-clock mr-2 text-[#006633]"></i>
  20. Lun - Ven: 8h00 - 16h30
  21. </span>
  22. </div>
  23. <!-- Réseaux sociaux + sélecteur de langue -->
  24. <div class="flex items-center space-x-4">
  25. <a href="#" class="text-gray-500 hover:text-[#006633] transition">
  26. <i class="fab fa-facebook-f"></i>
  27. </a>
  28. <a href="#" class="text-gray-500 hover:text-[#006633] transition">
  29. <i class="fab fa-twitter"></i>
  30. </a>
  31. <a href="#" class="text-gray-500 hover:text-[#006633] transition">
  32. <i class="fab fa-linkedin-in"></i>
  33. </a>
  34. <span class="text-gray-300">|</span>
  35. <!-- Sélecteur de langue -->
  36. <div class="relative" id="lang-switcher">
  37. <button type="button" id="lang-btn"
  38. onclick="toggleLangMenu()"
  39. class="flex items-center gap-2 text-gray-600 hover:text-[#006633]
  40. transition font-medium border border-gray-200
  41. hover:border-[#006633]/40 rounded-xl px-3 py-1.5 bg-white">
  42. <img src="https://flagcdn.com/w20/fr.png"
  43. id="lang-flag" class="w-4 rounded-sm">
  44. <span id="lang-label" class="text-sm">Français</span>
  45. <i id="lang-chevron"
  46. class="fas fa-chevron-down text-[10px] text-gray-400
  47. transition-transform duration-200"></i>
  48. </button>
  49. <!-- Dropdown -->
  50. <div id="lang-menu"
  51. class="absolute right-0 top-full mt-2 w-44 bg-white
  52. border border-gray-100 rounded-xl shadow-lg
  53. overflow-hidden z-50 hidden">
  54. <button type="button" id="lang-opt-fr"
  55. onclick="switchLanguage('fr')"
  56. class="w-full flex items-center gap-3 px-4 py-3 text-sm
  57. transition text-[#006633] font-semibold
  58. bg-emerald-50/60 hover:bg-emerald-50">
  59. <img src="https://flagcdn.com/w20/fr.png" class="w-4 rounded-sm">
  60. <span>Français</span>
  61. <i class="fas fa-check text-[#006633] text-xs ml-auto lang-check-fr"></i>
  62. </button>
  63. <div class="h-px bg-gray-100"></div>
  64. <button type="button" id="lang-opt-en"
  65. onclick="switchLanguage('en')"
  66. class="w-full flex items-center gap-3 px-4 py-3 text-sm
  67. transition text-gray-700
  68. hover:bg-gray-50 hover:text-[#006633]">
  69. <img src="https://flagcdn.com/w20/gb.png" class="w-4 rounded-sm">
  70. <span>English</span>
  71. <i class="fas fa-check text-[#006633] text-xs ml-auto lang-check-en hidden"></i>
  72. </button>
  73. </div>
  74. </div>
  75. </div>
  76. </div>
  77. </div>
  78. </div>
  79. <!-- Navigation principale -->
  80. <div class="flex justify-between items-center py-3 md:py-4">
  81. <!-- Logo -->
  82. <a href="{{ path('app_home') }}">
  83. <div class="flex items-center space-x-2 md:space-x-3">
  84. <img src="{{ asset('images/path6.png') }}"
  85. alt="Logo Journal Officiel"
  86. class="w-10 h-10 md:w-12 md:h-12 object-contain rounded-lg shadow-md">
  87. <div>
  88. <h1 class="text-base md:text-xl font-bold text-gray-800 tracking-tight">
  89. <span class="md:hidden">Journal Officiel</span>
  90. <span class="hidden md:inline">JOURNAL OFFICIEL</span>
  91. </h1>
  92. <p class="hidden md:block text-xs text-gray-500">Union des Comores</p>
  93. </div>
  94. </div>
  95. </a>
  96. <!-- Menu desktop -->
  97. <nav class="hidden lg:flex items-center space-x-1 xl:space-x-2">
  98. <a href="{{ path('app_home') }}"
  99. class="font-medium transition py-1.5 px-3 rounded-lg
  100. {{ route == 'app_home'
  101. ? 'bg-[#006633] text-white shadow-sm'
  102. : 'text-gray-700 hover:text-[#006633] hover:bg-green-50' }}">
  103. Accueil
  104. </a>
  105. <a href="{{ path('app_journal_officiel') }}"
  106. class="font-medium transition py-1.5 px-3 rounded-lg
  107. {{ route == 'app_journal_officiel'
  108. ? 'bg-[#006633] text-white shadow-sm'
  109. : 'text-gray-700 hover:text-[#006633] hover:bg-green-50' }}">
  110. Journal Officiel
  111. </a>
  112. <a href="{{ path('app_munganyo') }}"
  113. class="font-medium transition py-1.5 px-3 rounded-lg
  114. {{ route == 'app_munganyo'
  115. ? 'bg-[#006633] text-white shadow-sm'
  116. : 'text-gray-700 hover:text-[#006633] hover:bg-green-50' }}">
  117. Munganyo
  118. </a>
  119. <a href="{{ path('app_publications') }}"
  120. class="font-medium transition py-1.5 px-3 rounded-lg
  121. {{ route == 'app_publications'
  122. ? 'bg-[#006633] text-white shadow-sm'
  123. : 'text-gray-700 hover:text-[#006633] hover:bg-green-50' }}">
  124. Publications
  125. </a>
  126. <a href="{{ path('app_search') }}"
  127. class="font-medium transition py-1.5 px-3 rounded-lg
  128. {{ route == 'app_search'
  129. ? 'bg-[#006633] text-white shadow-sm'
  130. : 'text-gray-700 hover:text-[#006633] hover:bg-green-50' }}">
  131. <i class="fas fa-search mr-1"></i> Recherche
  132. </a>
  133. </nav>
  134. <!-- Actions droite -->
  135. <div class="flex items-center space-x-2 md:space-x-4">
  136. {% if app.user %}
  137. <div class="relative group">
  138. <button class="flex items-center space-x-1 md:space-x-2
  139. text-gray-700 hover:text-[#006633] transition">
  140. <i class="fas fa-user-circle text-xl md:text-2xl"></i>
  141. <span class="hidden md:inline text-sm">
  142. {{ app.user.firstName|default('Utilisateur') }}
  143. </span>
  144. <i class="fas fa-chevron-down text-xs hidden md:inline"></i>
  145. </button>
  146. <div class="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg
  147. opacity-0 invisible group-hover:opacity-100
  148. group-hover:visible transition-all z-50">
  149. <a href="{{ path('app_dashboard') }}"
  150. class="block px-4 py-2 text-gray-700 hover:bg-gray-50">
  151. <i class="fas fa-tachometer-alt mr-2"></i> Tableau de bord
  152. </a>
  153. <a href="{{ path('app_abonn') }}"
  154. class="block px-4 py-2 text-gray-700 hover:bg-gray-50">
  155. <i class="fas fa-crown mr-2"></i> Abonnement
  156. </a>
  157. <div class="border-t"></div>
  158. <a href="{{ path('app_logout') }}"
  159. class="block px-4 py-2 text-red-600 hover:bg-gray-50">
  160. <i class="fas fa-sign-out-alt mr-2"></i> Déconnexion
  161. </a>
  162. </div>
  163. </div>
  164. {% else %}
  165. <a href="{{ path('app_login') }}"
  166. class="text-gray-700 hover:text-[#006633] transition font-medium text-sm md:text-base">
  167. <i class="fas fa-user mr-0 md:mr-1"></i>
  168. <span class="hidden sm:inline">Connexion</span>
  169. </a>
  170. <a href="{{ path('app_abonn') }}"
  171. class="bg-gradient-to-r from-[#006633] to-[#008844] text-white
  172. px-2 md:px-5 py-1.5 md:py-2 rounded-lg
  173. hover:from-[#004d26] hover:to-[#006633]
  174. transition shadow-md hover:shadow-lg
  175. text-xs md:text-base whitespace-nowrap">
  176. <i class="fas fa-gem mr-0 md:mr-1 text-xs md:text-base"></i>
  177. <span class="hidden sm:inline">S'abonner</span>
  178. <span class="sm:hidden">Abonner</span>
  179. </a>
  180. {% endif %}
  181. <!-- Bouton menu mobile -->
  182. <button id="mobileMenuButton"
  183. class="lg:hidden text-gray-700 hover:text-[#006633] transition p-2">
  184. <i class="fas fa-bars text-xl md:text-2xl"></i>
  185. </button>
  186. </div>
  187. </div>
  188. <!-- Menu mobile -->
  189. <div id="mobileMenu"
  190. class="lg:hidden hidden border-t border-gray-100 bg-white shadow-lg">
  191. <nav class="flex flex-col py-4">
  192. <a href="{{ path('app_home') }}"
  193. class="py-3 px-4 transition flex items-center space-x-3 border-l-4 font-medium
  194. {{ route == 'app_home'
  195. ? 'bg-green-50 text-[#006633] border-[#006633]'
  196. : 'text-gray-700 hover:text-[#006633] hover:bg-green-50 border-transparent hover:border-[#006633]' }}">
  197. <i class="fas fa-home text-[#006633] w-5"></i>
  198. <span>Accueil</span>
  199. </a>
  200. <a href="{{ path('app_journal_officiel') }}"
  201. class="py-3 px-4 transition flex items-center space-x-3 border-l-4 font-medium
  202. {{ route == 'app_journal_officiel'
  203. ? 'bg-green-50 text-[#006633] border-[#006633]'
  204. : 'text-gray-700 hover:text-[#006633] hover:bg-green-50 border-transparent hover:border-[#006633]' }}">
  205. <i class="fas fa-newspaper text-[#006633] w-5"></i>
  206. <span>Journal Officiel</span>
  207. </a>
  208. <a href="{{ path('app_munganyo') }}"
  209. class="py-3 px-4 transition flex items-center space-x-3 border-l-4 font-medium
  210. {{ route == 'app_munganyo'
  211. ? 'bg-green-50 text-[#006633] border-[#006633]'
  212. : 'text-gray-700 hover:text-[#006633] hover:bg-green-50 border-transparent hover:border-[#006633]' }}">
  213. <i class="fas fa-file-alt text-[#006633] w-5"></i>
  214. <span>Munganyo</span>
  215. </a>
  216. <a href="{{ path('app_publications') }}"
  217. class="py-3 px-4 transition flex items-center space-x-3 border-l-4 font-medium
  218. {{ route == 'app_publications'
  219. ? 'bg-green-50 text-[#006633] border-[#006633]'
  220. : 'text-gray-700 hover:text-[#006633] hover:bg-green-50 border-transparent hover:border-[#006633]' }}">
  221. <i class="fas fa-bullhorn text-[#006633] w-5"></i>
  222. <span>Publications</span>
  223. </a>
  224. <a href="{{ path('app_search') }}"
  225. class="py-3 px-4 transition flex items-center space-x-3 border-l-4 font-medium
  226. {{ route == 'app_search'
  227. ? 'bg-green-50 text-[#006633] border-[#006633]'
  228. : 'text-gray-700 hover:text-[#006633] hover:bg-green-50 border-transparent hover:border-[#006633]' }}">
  229. <i class="fas fa-search text-[#006633] w-5"></i>
  230. <span>Recherche avancée</span>
  231. </a>
  232. <!-- Sélecteur de langue mobile -->
  233. <div class="border-t border-gray-100 mt-2 pt-3 px-4">
  234. <p class="text-xs text-gray-400 uppercase tracking-widest mb-2 font-semibold"
  235. data-no-translate>
  236. Langue / Language
  237. </p>
  238. <div class="flex gap-2">
  239. <button onclick="switchLanguage('fr')"
  240. class="flex items-center gap-2 px-3 py-2 rounded-xl
  241. border border-gray-200 text-sm text-gray-700
  242. hover:border-[#006633] hover:text-[#006633] transition">
  243. <img src="https://flagcdn.com/w20/fr.png" class="w-4 rounded-sm">
  244. Français
  245. </button>
  246. <button onclick="switchLanguage('en')"
  247. class="flex items-center gap-2 px-3 py-2 rounded-xl
  248. border border-gray-200 text-sm text-gray-700
  249. hover:border-[#006633] hover:text-[#006633] transition">
  250. <img src="https://flagcdn.com/w20/gb.png" class="w-4 rounded-sm">
  251. English
  252. </button>
  253. </div>
  254. </div>
  255. <!-- Connexion / Déconnexion -->
  256. <div class="border-t border-gray-100 mt-2 pt-2">
  257. {% if not app.user %}
  258. <a href="{{ path('app_login') }}"
  259. class="text-gray-700 hover:text-[#006633] hover:bg-green-50
  260. py-3 px-4 transition flex items-center space-x-3">
  261. <i class="fas fa-sign-in-alt text-[#006633] w-5"></i>
  262. <span>Connexion</span>
  263. </a>
  264. <a href="{{ path('app_abonn') }}"
  265. class="bg-gradient-to-r from-[#006633] to-[#008844] text-white
  266. mx-4 mt-2 mb-1 py-2.5 px-4 rounded-lg transition
  267. flex items-center justify-center space-x-2 shadow-md">
  268. <i class="fas fa-gem"></i>
  269. <span class="font-semibold">S'abonner maintenant</span>
  270. </a>
  271. {% else %}
  272. <a href="{{ path('app_dashboard') }}"
  273. class="text-gray-700 hover:text-[#006633] hover:bg-green-50
  274. py-3 px-4 transition flex items-center space-x-3">
  275. <i class="fas fa-tachometer-alt text-[#006633] w-5"></i>
  276. <span>Tableau de bord</span>
  277. </a>
  278. <a href="{{ path('app_logout') }}"
  279. class="text-red-600 hover:bg-red-50 py-3 px-4
  280. transition flex items-center space-x-3">
  281. <i class="fas fa-sign-out-alt text-red-600 w-5"></i>
  282. <span>Déconnexion</span>
  283. </a>
  284. {% endif %}
  285. </div>
  286. </nav>
  287. </div>
  288. </div>
  289. </header>
  290. <style>
  291. @media (max-width: 480px) {
  292. .whitespace-nowrap { font-size: .7rem; padding-left: .5rem; padding-right: .5rem; }
  293. .whitespace-nowrap i { font-size: .65rem; }
  294. }
  295. #mobileMenu { max-height: 80vh; overflow-y: auto; scrollbar-width: thin; }
  296. #mobileMenu::-webkit-scrollbar { width: 4px; }
  297. #mobileMenu::-webkit-scrollbar-track { background: #f1f1f1; }
  298. #mobileMenu::-webkit-scrollbar-thumb { background: #006633; border-radius: 4px; }
  299. </style>
  300. <script>
  301. // ── Menu mobile ──────────────────────────────────────────────
  302. const mobileMenuButton = document.getElementById('mobileMenuButton');
  303. const mobileMenu = document.getElementById('mobileMenu');
  304. if (mobileMenuButton && mobileMenu) {
  305. mobileMenuButton.addEventListener('click', function () {
  306. const isHidden = mobileMenu.classList.contains('hidden');
  307. if (isHidden) {
  308. mobileMenu.classList.remove('hidden');
  309. mobileMenu.style.animation = 'slideDown 0.3s ease-out';
  310. this.innerHTML = '<i class="fas fa-times text-xl md:text-2xl"></i>';
  311. } else {
  312. mobileMenu.style.animation = 'slideUp 0.3s ease-out';
  313. setTimeout(() => mobileMenu.classList.add('hidden'), 250);
  314. this.innerHTML = '<i class="fas fa-bars text-xl md:text-2xl"></i>';
  315. }
  316. });
  317. mobileMenu.querySelectorAll('a').forEach(link => {
  318. link.addEventListener('click', () => {
  319. mobileMenu.classList.add('hidden');
  320. mobileMenuButton.innerHTML = '<i class="fas fa-bars text-xl md:text-2xl"></i>';
  321. });
  322. });
  323. }
  324. // Animations menu mobile
  325. const _s = document.createElement('style');
  326. _s.textContent = `
  327. @keyframes slideDown {
  328. from { opacity: 0; transform: translateY(-10px); }
  329. to { opacity: 1; transform: translateY(0); }
  330. }
  331. @keyframes slideUp {
  332. from { opacity: 1; transform: translateY(0); }
  333. to { opacity: 0; transform: translateY(-10px); }
  334. }
  335. `;
  336. document.head.appendChild(_s);
  337. </script>