1<!doctype html> 2<html lang="fr" class="h-full"> 3<head> 4 <meta charset="utf-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1"> 6 <meta name="color-scheme" content="light dark"> 7 <title>FabLab66 â Communauté des makers des Pyrénées-Orientales</title> 8 <link rel="icon" href="/static/img/favicon.ico" sizes="any"> 9 <link rel="icon" href="/static/img/favicon-64.png" type="image/png" sizes="64x64"> 10 <link rel="apple-touch-icon" href="/static/img/favicon-180.png"> 11 12 13 <meta name="description" content="FabLab66 relie fablabs, tiers-lieux et makers des Pyrénées-Orientales. Projets documentés, matériel partagé, ateliers."> 14 <link rel="canonical" href="https://fablab66.fr/"> 15 <meta property="og:site_name" content="FabLab66"> 16 <meta property="og:locale" content="fr_FR"> 17 <meta property="og:type" content="website"> 18 <meta property="og:title" content="FabLab66 â Communauté des makers des Pyrénées-Orientales"> 19 <meta property="og:description" content="FabLab66 relie fablabs, tiers-lieux et makers des Pyrénées-Orientales. Projets documentés, matériel partagé, ateliers."> 20 <meta property="og:url" content="https://fablab66.fr/"> 21 <meta property="og:image" content="https://fablab66.fr/static/img/logo.png"> 22 <meta name="twitter:card" content="summary_large_image"> 23 <meta name="twitter:title" content="FabLab66 â Communauté des makers des Pyrénées-Orientales"> 24 <meta name="twitter:description" content="FabLab66 relie fablabs, tiers-lieux et makers des Pyrénées-Orientales. Projets documentés, matériel partagé, ateliers."> 25 <meta name="twitter:image" content="https://fablab66.fr/static/img/logo.png"> 26 27
27<script> 28 // Apply theme BEFORE first paint to avoid flash. 29 (function () { 30 try { 31 var stored = localStorage.getItem('theme'); 32 var systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches; 33 var dark = stored === 'dark' || (stored === null && systemDark); 34 if (dark) document.documentElement.classList.add('dark'); 35 } catch (_) {} 36 })(); 37 </script>
37 38 39
39<script src="https://cdn.tailwindcss.com"></script>
39 40
40<script src="https://unpkg.com/[email protected]" defer></script>
40 41
41<script> 42 tailwind.config = { 43 darkMode: 'class', 44 theme: { 45 extend: { 46 colors: { 47 brand: { 48 50: '#f0f7fd', 100: '#d9eafa', 200: '#b2d5f5', 300: '#7fb8ed', 49 400: '#4a9be3', 500: '#1F88DB', 600: '#166fb8', 700: '#135a95', 50 800: '#124b78', 900: '#123f64' 51 } 52 }, 53 fontFamily: { sans: ['Inter','ui-sans-serif','system-ui'] } 54 } 55 } 56 } 57 </script>
57 58 <link rel="preconnect" href="https://fonts.googleapis.com"> 59 <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> 60 61 62 <link rel="stylesheet" 63 href="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/github.min.css" 64 media="(prefers-color-scheme: light)"> 65 <link rel="stylesheet" 66 href="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/github-dark.min.css" 67 media="(prefers-color-scheme: dark)"> 68
68<script defer src="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/highlight.min.js"></script>
68 69 70 71 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/cropper.min.css"> 72 73 74</head> 75<body class="min-h-full flex flex-col bg-slate-50 text-slate-800 font-sans antialiased 76 dark:bg-slate-950 dark:text-slate-200"> 77 <nav class="bg-white border-b border-slate-200 sticky top-0 z-40 78 dark:bg-slate-900 dark:border-slate-800"> 79 <div class="max-w-5xl mx-auto px-4"> 80 81 82 <div class="h-14 flex items-center justify-between gap-2"> 83 84 85 <a href="/" 86 class="flex items-center gap-2 font-bold text-brand-700 dark:text-brand-400 text-lg shrink-0"> 87 <img src="/static/img/logo.png" alt="FabLab66" class="w-9 h-9"> 88 <span class="hidden xs:inline">FabLab66</span> 89 </a> 90 91 92 <div class="hidden sm:flex items-center gap-1 sm:gap-2 text-sm flex-1 justify-end"> 93 <a class="px-2.5 py-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 whitespace-nowrap" href="/posts/">Feed</a> 94 <a class="px-2.5 py-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 whitespace-nowrap" href="/projects/">Projets</a> 95 <a class="px-2.5 py-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 whitespace-nowrap hidden md:inline" href="/equipment/">
95Matériel</a> 96 <a class="px-2.5 py-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 whitespace-nowrap hidden md:inline" href="/events/">Ãvénements</a> 97 <a class="px-2.5 py-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 whitespace-nowrap hidden lg:inline" href="/communities/">Communautés</a> 98 <a class="px-2.5 py-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 whitespace-nowrap hidden md:inline" href="/membres">Membres</a> 99 100 <button type="button" onclick="window.__toggleTheme()" 101 class="p-2 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-600 dark:text-slate-300" 102 title="Changer de thème" aria-label="Changer de thème"> 103 <svg class="w-5 h-5 hidden dark:block" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor"> 104 <path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2.25m6.364 1.386-1.591 1.591M21 12h-2.25m-1.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z"/> 105 </svg> 106 <svg class="w-5 h-5 dark:hidden" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor"> 107 <path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z"/> 108 </svg> 109 </button> 110 111 112 <a href="/auth/login" 113 class="px-2.5 py-1.5 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 whitespace-nowrap">Se connecter</a> 114 <a href="/auth/register" 115 class="px-2.5 py-1.5 rounded-lg bg-brand-500 text-white hover:bg-brand-600 whitespace-nowrap">Créer un compte</a> 116 117 </div> 118 119 120 <div class="flex sm:hidden items-center gap-1"> 121 122 <button type="button" id="nav-burger" 123 class="p-2 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-600 dark:text-slate-300" 124 aria-label="Menu" aria-expanded="false" aria-controls="mobile-menu"> 125 <svg id="burger-icon" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"> 126 <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"/> 127 </svg> 128 <svg id="burger-close-icon" class="w-5 h-5 hidden" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"> 129 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 130 </svg> 131 </button> 132 </div> 133 </div> 134 135 136 <div id="mobile-menu" class="hidden sm:hidden border-t border-slate-200 dark:border-slate-800 py-3 space-y-0.5 text-sm"> 137 138 139 <a href="/posts/" 140 class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-700 dark:text-slate-200"> 141 Feed 142 </a> 143 <a href="/projects/" 144 class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-700 dark:text-slate-200"> 145 Projets 146 </a> 147 <a href="/equipment/" 148 class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-700 dark:text-slate-200"> 149 Matériel 150 </a> 151 <a href="/events/" 152 class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-700 dark:text-slate-200"> 153 Ãvénements 154 </a> 155 <a href="/communities/" 156 class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-700 dark:text-slate-200"> 157 Communautés 158 </a> 159 <a href="/membres" 160 class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-700 dark:text-slate-200"> 161 Membres 162 </a> 163 164 165 <button type="button" onclick="window.__toggleTheme()" 166 class="w-full flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-slate-100 dar
166k:hover:bg-slate-800 text-slate-700 dark:text-slate-200"> 167 <svg class="w-4 h-4 hidden dark:block" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor"> 168 <path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2.25m6.364 1.386-1.591 1.591M21 12h-2.25m-1.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z"/> 169 </svg> 170 <svg class="w-4 h-4 dark:hidden" fill="none" viewBox="0 0 24 24" stroke-width="1.75" stroke="currentColor"> 171 <path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z"/> 172 </svg> 173 Changer de thème 174 </button> 175 176 <div class="my-1 border-t border-slate-100 dark:border-slate-800"></div> 177 178 179 <a href="/auth/login" 180 class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-700 dark:text-slate-200"> 181 Se connecter 182 </a> 183 <a href="/auth/register" 184 class="flex items-center gap-3 mx-3 my-1 px-4 py-2 rounded-lg bg-brand-500 text-white hover:bg-brand-600 font-medium justify-center"> 185 Créer un compte 186 </a> 187 188 </div> 189 190 </div> 191</nav> 192
193<script> 194 // Admin dropdown close on outside click 195 document.addEventListener('click', function(e) { 196 var wrap = document.querySelector('[data-admin-dropdown]'); 197 var menu = document.getElementById('admin-menu'); 198 if (wrap && menu && !wrap.contains(e.target)) menu.classList.add('hidden'); 199 }); 200 201 // Mobile burger toggle 202 (function() { 203 var burger = document.getElementById('nav-burger'); 204 var menu = document.getElementById('mobile-menu'); 205 var iconOpen = document.getElementById('burger-icon'); 206 var iconClose = document.getElementById('burger-close-icon'); 207 if (!burger || !menu) return; 208 burger.addEventListener('click', function() { 209 var open = !menu.classList.contains('hidden'); 210 menu.classList.toggle('hidden', open); 211 iconOpen.classList.toggle('hidden', !open); 212 iconClose.classList.toggle('hidden', open); 213 burger.setAttribute('aria-expanded', String(!open)); 214 }); 215 })(); 216</script>
216 217 218 219 220 221 222 <main class="flex-1 w-full"> 223 224 225 <section class="bg-gradient-to-br from-brand-50 via-white to-slate-50 border-b border-slate-200 226 dark:from-brand-900/30 dark:via-slate-950 dark:to-slate-950 dark:border-slate-800"> 227 <div class="max-w-5xl mx-auto px-4 py-16 sm:py-24 text-center"> 228 <img src="/static/img/logo.png" alt="FabLab66" 229 class="w-28 h-28 sm:w-32 sm:h-32 mx-auto mb-6 drop-shadow-sm"> 230 <h1 class="text-4xl sm:text-5xl font-bold text-slate-900 dark:text-white tracking-tight"> 231 Fabriquer, apprendre, partager <span class="text-brand-500">ensemble</span> 232 </h1> 233 <p class="mt-4 max-w-2xl mx-auto text-slate-600 dark:text-slate-300 text-lg"> 234 La plateforme qui relie fablabs, tiers-lieux, associations et bricoleurs 235 des Pyrénées-Orientales. Documentez vos projets, partagez votre matériel, 236 proposez ou rejoignez des formations. 237 </p> 238 <div class="mt-8 flex flex-wrap justify-center gap-3"> 239 240 <a href="/auth/register" class="px-5 py-2.5 rounded-lg bg-brand-500 text-white font-medium hover:bg-brand-600">Créer un compte</a> 241 <a href="/auth/login" 242 class="px-5 py-2.5 rounded-lg bg-white border border-slate-300 hover:bg-slate-50 243 dark:bg-slate-900 dark:border-slate-700 dark:hover:bg-slate-800 dark:text-slate-100">Se connecter</a> 244 245 </div> 246 </div> 247 </section> 248 249 250 <section class="bg-white dark:bg-slate-900 border-b border-slate-200 dark:border-slate-800"> 251 <div class="max-w-5xl mx-auto px-4 py-6 grid grid-cols-2 sm:grid-cols-4 gap-4 text-center"> 252 253 <a href="/projects/" class="block hover:opacity-80 transition"> 254 <div class="text-3xl font-bold text-brand-600 dark:text-brand-400">233</div> 255 <div class="text-xs uppercase tracking-wide text-slate-500 dark:text-slate-400 mt-1">Projets</div> 256 </a> 257 258 <a href="/communities/" class="block hover:opacity-80 transition"> 259 <div class="text-3xl font-bold text-brand-600 dark:text-brand-400">4</div> 260 <div class="text-xs uppercase tracking-wide text-slate-500 dark:text-slate-400 mt-1">Communautés</div> 261 </a> 262 263 <a href="/events/" class="block hover:opacity-80 transition"> 264 <div class="text-3xl font-bold text-brand-600 dark:text-brand-400">0</div> 265 <div class="text-xs uppercase tracking-wide text-slate-500 dark:text-slate-400 mt-1">Ãvénements</div> 266 </a> 267 268 <div> 269 <div class="text-3xl font-bold text-brand-600 dark:text-brand-400">24</div> 270 <div class="text-xs uppercase tracking-wide text-slate-500 dark:text-slate-400 mt-1">Makers</div> 271 </div> 272 273 </div> 274 </section> 275 276 277 278 <section class="max-w-6xl mx-auto px-4 py-12"> 279 <div class="flex items-end justify-between mb-6 gap-3 flex-wrap"> 280 <div> 281 <h2 class="text-2xl font-bold text-slate-900 dark:text-white">Projets récents</h2> 282 <p class="text-sm text-slate-500 dark:text-slate-400 mt-1">Les dernières créations partagées par la communauté.</p> 283 </div> 284 <a href="/projects/" 285 class="text-sm text-brand-600 dark:text-brand-400 hover:underline">Tous les projets â</a> 286 </div> 287 288 <div class="relative group" data-carousel> 289 <button type="button" data-carousel-prev 290 class="hidden md:grid absolute -left-4 top-1/2 -translate-y-1/2 z-10 w-10 h-10 rounded-full bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 shadow-md place-items-center text-slate-700 dark:text-slate-200 hover:bg-brand-50 hover:text-brand-600 dark:hover:bg-brand-900/40 dark:hover:text-brand-300 opacity-0 group-hover:opacity-100 transition" 291 aria-label="Précédent"> 292 <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"> 293 <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5"/> 294 </svg> 295 </button> 296 <button type="button" data-carousel-next 297 class="hidden md:grid absolute -right-4 top-1/2 -translate-y-1/2 z-10 w-10 h-10 rounded-full bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 shadow-md place-items-center text-slate-700 dark:text-slate-200 hover:bg-brand-50 hover:text-brand-600 dark:hover:bg-brand-900/40 dark:hover:text-brand-300 opacity-0 group-hover:opacity-100 transition" 298 aria-label="Suivant"> 299 <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"> 300 <path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5"/> 301 </svg> 302 </button> 303 304 <div data-carousel-track 305 class="flex gap-5 overflow-x-auto snap-x snap-mandatory scroll-smooth pb-4 -mx-4 px-4" 306 style="scrollbar-width: thin;"> 307 308 309 <div class="snap-start shrink-0 w-[85%] sm:w-[45%] lg:w-[31%]"> 310 311<a href="/projects/jukebox-20" 312 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl overflow-hidden shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition">
313 <div class="aspect-[16/10] bg-slate-100 dark:bg-slate-800 overflow-hidden"> 314 315 <img src="/uploads/project_covers/4c7980e6ec284d85bdbc2d85f73e3ec6.jpg" 316 alt="" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"> 317 318 </div> 319 <div class="p-4"> 320 <h2 class="font-semibold text-slate-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 line-clamp-2"> 321 JukeBox 2.0 322 323 <span class="ml-1 text-xs font-medium px-1.5 py-0.5 rounded-full bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300">ð§ en cours</span> 324 325 </h2> 326 327 <p class="mt-1 text-sm text-slate-600 dark:text-slate-400 line-clamp-2">Redonner vie à un jukebox de 1972 Century 21</p> 328 329 <div class="mt-3 flex flex-wrap gap-1.5"> 330 331 <span class="text-xs px-2 py-0.5 rounded-full bg-brand-50 text-brand-700 dark:bg-brand-900/40 dark:text-brand-300">Musique</span> 332 333 334 <span class="text-xs px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300" title="FabLab">ð FabLab Maillol</span> 335 336 </div> 337 <div class="mt-3 text-xs text-slate-500 dark:text-slate-500 flex items-center justify-between"> 338 <span class="truncate">par Fabien</span> 339 <span class="flex items-center gap-2 shrink-0"> 340 <span class="inline-flex items-center gap-1" title="J'aime"> 341 <svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24"> 342 <path d="M12 21s-7-4.35-9.5-8.5C.7 9.4 2.6 5 6.5 5 8.6 5 10.4 6 12 7.5 13.6 6 15.4 5 17.5 5c3.9 0 5.8 4.4 4 7.5C19 16.65 12 21 12 21z"/> 343 </svg> 344 0 345 </span> 346 <span class="inline-flex items-center gap-1" title="Consultations"> 347 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 348 <path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"/> 349 <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> 350 </svg> 351 319 352 </span> 353 <span class="inline-flex items-center gap-1" title="Commentaires"> 354 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 355 <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8-1.34 0-2.61-.26-3.76-.72L3 20l1.72-4.24C4.26 14.61 4 13.34 4 12c0-4.418 4.03-8 9-8s8 3.582 8 8z"/> 356 </svg> 357 0 358 </span> 359 360 </span> 361 </div> 362 </div> 363</a> 364 </div> 365 366 367 368 <div class="snap-start shrink-0 w-[85%] sm:w-[45%] lg:w-[31%]"> 369 370<a href="/projects/antenne-parabolique-amplication-4g" 371 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl overflow-hidden shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 372 <div class="aspect-[16/10] bg-slate-100 dark:bg-slate-800 overflow-hidden"> 373 374 <img src="/uploads/project_covers/e46785cfc68744b2aad7da1a5137e00f.png" 375 alt="" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"> 376 377 </div> 378 <div class="p-4"> 379 <h2 class="font-semibold text-slate-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 line-clamp-2"> 380 Antenne parabolique amplication 4G 381 382 <span class="ml-1 text-xs font-medium px-1.5 py-0.5 rounded-full bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300">ð§ en cours</span> 383 384 </h2> 385 386 <p class="mt-1 text-sm text-slate-600 dark:text-slate-400 line-clamp-2">Réflecteur Parabolique Passif pour Routeur 4G Huawei</p> 387 388 <div class="mt-3 flex flex-wrap gap-1.5"> 389
390 <span class="text-xs px-2 py-0.5 rounded-full bg-brand-50 text-brand-700 dark:bg-brand-900/40 dark:text-brand-300">Vie quotidienne</span> 391 392 393 <span class="text-xs px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300" title="FabLab">ð Mobilab 66</span> 394 395 </div> 396 <div class="mt-3 text-xs text-slate-500 dark:text-slate-500 flex items-center justify-between"> 397 <span class="truncate">par Fabien</span> 398 <span class="flex items-center gap-2 shrink-0"> 399 <span class="inline-flex items-center gap-1" title="J'aime"> 400 <svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24"> 401 <path d="M12 21s-7-4.35-9.5-8.5C.7 9.4 2.6 5 6.5 5 8.6 5 10.4 6 12 7.5 13.6 6 15.4 5 17.5 5c3.9 0 5.8 4.4 4 7.5C19 16.65 12 21 12 21z"/> 402 </svg> 403 0 404 </span> 405 <span class="inline-flex items-center gap-1" title="Consultations"> 406 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 407 <path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"/> 408 <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> 409 </svg> 410 208 411 </span> 412 <span class="inline-flex items-center gap-1" title="Commentaires"> 413 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 414 <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8-1.34 0-2.61-.26-3.76-.72L3 20l1.72-4.24C4.26 14.61 4 13.34 4 12c0-4.418 4.03-8 9-8s8 3.582 8 8z"/> 415 </svg> 416 0 417 </span> 418 419 </span> 420 </div> 421 </div> 422</a> 423 </div> 424 425 426 427 <div class="snap-start shrink-0 w-[85%] sm:w-[45%] lg:w-[31%]"> 428 429<a href="/projects/subaru-impreza-rc-110" 430 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl overflow-hidden shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 431 <div class="aspect-[16/10] bg-slate-100 dark:bg-slate-800 overflow-hidden"> 432 433 <img src="/uploads/project_covers/4f77ce0c3cba4f8bb1d1d6a937416188.jpg" 434 alt="" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"> 435 436 </div> 437 <div class="p-4"> 438 <h2 class="font-semibold text-slate-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 line-clamp-2"> 439 Subaru Impreza RC 1/10 440 441 </h2> 442 443 <p class="mt-1 text-sm text-slate-600 dark:text-slate-400 line-clamp-2">Impression 3D, Raspberry Pi, et 4G.</p> 444 445 <div class="mt-3 flex flex-wrap gap-1.5"> 446 447 <span class="text-xs px-2 py-0.5 rounded-full bg-brand-50 text-brand-700 dark:bg-brand-900/40 dark:text-brand-300">Robotique</span> 448 449 450 <span class="text-xs px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300" title="FabLab">ð La Cyber Fabrique</span> 451 452 </div> 453 <div class="mt-3 text-xs text-slate-500 dark:text-slate-500 flex items-center justify-between"> 454 <span class="truncate">par Kévin CHAILLY</span> 455 <span class="flex items-center gap-2 shrink-0"> 456 <span class="inline-flex items-center gap-1" title="J'aime"> 457 <svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24"> 458 <path d="M12 21s-7-4.35-9.5-8.5C.7 9.4 2.6 5 6.5 5 8.6 5 10.4 6 12 7.5 13.6 6 15.4 5 17.5 5c3.9 0 5.8 4.4 4 7.5C19 16.65 12 21 12 21z"/> 459 </svg> 460 0 461 </span> 462 <span class="inline-flex items-center gap-1" title="Consultations"> 463 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 464 <path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"/>
464 465 <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> 466 </svg> 467 329 468 </span> 469 <span class="inline-flex items-center gap-1" title="Commentaires"> 470 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 471 <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8-1.34 0-2.61-.26-3.76-.72L3 20l1.72-4.24C4.26 14.61 4 13.34 4 12c0-4.418 4.03-8 9-8s8 3.582 8 8z"/> 472 </svg> 473 0 474 </span> 475 <span>05/07/2026</span> 476 </span> 477 </div> 478 </div> 479</a> 480 </div> 481 482 483 484 <div class="snap-start shrink-0 w-[85%] sm:w-[45%] lg:w-[31%]"> 485 486<a href="/projects/cyberdeck" 487 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl overflow-hidden shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 488 <div class="aspect-[16/10] bg-slate-100 dark:bg-slate-800 overflow-hidden"> 489 490 <img src="/uploads/project_covers/fff5d6511b7a4b90836f7c4beebceb3e.jpg" 491 alt="" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"> 492 493 </div> 494 <div class="p-4"> 495 <h2 class="font-semibold text-slate-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 line-clamp-2"> 496 Cyberdeck 497 498 </h2> 499 500 <p class="mt-1 text-sm text-slate-600 dark:text-slate-400 line-clamp-2">Un PC Fixe dans une Pelicase</p> 501 502 <div class="mt-3 flex flex-wrap gap-1.5"> 503 504 <span class="text-xs px-2 py-0.5 rounded-full bg-brand-50 text-brand-700 dark:bg-brand-900/40 dark:text-brand-300">Jeux</span> 505 506 507 <span class="text-xs px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300" title="FabLab">ð La Cyber Fabrique</span> 508 509 </div> 510 <div class="mt-3 text-xs text-slate-500 dark:text-slate-500 flex items-center justify-between"> 511 <span class="truncate">par Kévin CHAILLY</span> 512 <span class="flex items-center gap-2 shrink-0"> 513 <span class="inline-flex items-center gap-1" title="J'aime"> 514 <svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24"> 515 <path d="M12 21s-7-4.35-9.5-8.5C.7 9.4 2.6 5 6.5 5 8.6 5 10.4 6 12 7.5 13.6 6 15.4 5 17.5 5c3.9 0 5.8 4.4 4 7.5C19 16.65 12 21 12 21z"/> 516 </svg> 517 1 518 </span> 519 <span class="inline-flex items-center gap-1" title="Consultations"> 520 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 521 <path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"/> 522 <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> 523 </svg> 524 402 525 </span> 526 <span class="inline-flex items-center gap-1" title="Commentaires"> 527 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 528 <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8-1.34 0-2.61-.26-3.76-.72L3 20l1.72-4.24C4.26 14.61 4 13.34 4 12c0-4.418 4.03-8 9-8s8 3.582 8 8z"/> 529 </svg> 530 0 531 </span> 532 <span>05/07/2026</span> 533 </span> 534 </div> 535 </div> 536</a> 537 </div> 538 539 540 541 <div class="snap-start shrink-0 w-[85%] sm:w-[45%] lg:w-[31%]"> 542 543<a href="/projects/cnc-mpcnc-3-axes" 544 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl overflow-hidden shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition">
545 <div class="aspect-[16/10] bg-slate-100 dark:bg-slate-800 overflow-hidden"> 546 547 <img src="/uploads/project_covers/6497faea5ea143bc820d016c24a33f38.jpg" 548 alt="" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"> 549 550 </div> 551 <div class="p-4"> 552 <h2 class="font-semibold text-slate-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 line-clamp-2"> 553 CNC MPCNC 3 Axes 554 555 </h2> 556 557 <p class="mt-1 text-sm text-slate-600 dark:text-slate-400 line-clamp-2">Projet de construction d'une CNC mpcnc 3 axes</p> 558 559 <div class="mt-3 flex flex-wrap gap-1.5"> 560 561 <span class="text-xs px-2 py-0.5 rounded-full bg-brand-50 text-brand-700 dark:bg-brand-900/40 dark:text-brand-300">Autre</span> 562 563 564 <span class="text-xs px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300" title="FabLab">ð La Cyber Fabrique</span> 565 566 </div> 567 <div class="mt-3 text-xs text-slate-500 dark:text-slate-500 flex items-center justify-between"> 568 <span class="truncate">par Kévin CHAILLY</span> 569 <span class="flex items-center gap-2 shrink-0"> 570 <span class="inline-flex items-center gap-1" title="J'aime"> 571 <svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24"> 572 <path d="M12 21s-7-4.35-9.5-8.5C.7 9.4 2.6 5 6.5 5 8.6 5 10.4 6 12 7.5 13.6 6 15.4 5 17.5 5c3.9 0 5.8 4.4 4 7.5C19 16.65 12 21 12 21z"/> 573 </svg> 574 1 575 </span> 576 <span class="inline-flex items-center gap-1" title="Consultations"> 577 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 578 <path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"/> 579 <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> 580 </svg> 581 324 582 </span> 583 <span class="inline-flex items-center gap-1" title="Commentaires"> 584 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 585 <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8-1.34 0-2.61-.26-3.76-.72L3 20l1.72-4.24C4.26 14.61 4 13.34 4 12c0-4.418 4.03-8 9-8s8 3.582 8 8z"/> 586 </svg> 587 1 588 </span> 589 <span>05/07/2026</span> 590 </span> 591 </div> 592 </div> 593</a> 594 </div> 595 596 597 598 <div class="snap-start shrink-0 w-[85%] sm:w-[45%] lg:w-[31%]"> 599 600<a href="/projects/support-pour-panneaux-solaire" 601 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl overflow-hidden shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 602 <div class="aspect-[16/10] bg-slate-100 dark:bg-slate-800 overflow-hidden"> 603 604 <img src="/uploads/project_covers/6fe6612229394dc88f73eb2bc46547d6.jpg" 605 alt="" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"> 606 607 </div> 608 <div class="p-4"> 609 <h2 class="font-semibold text-slate-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 line-clamp-2"> 610 Support pour panneaux solaire 611 612 </h2> 613 614 <p class="mt-1 text-sm text-slate-600 dark:text-slate-400 line-clamp-2">Ce support sert à accrocher un panneau solaire sur un trépied de chantier, afin de faciliter l'installation et le déplacement des panneaux.</p> 615 616 <div class="mt-3 flex flex-wrap gap-1.5"> 617 618 <span class="text-xs px-2 py-0.5 rounded-full bg-brand-50 text-brand-700 dark:bg-brand-900/40 dark:text-brand-300">Vie quotidienne</span> 619 620 621 <span class="text-xs px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300" title="FabLab">ð La Cyber Fabrique</span> 622 623 </div> 624 <div class="mt-3 text-xs text-slate-500 dark:text-slate-500 flex items-center justify-between">
625 <span class="truncate">par Romain Llapasset</span> 626 <span class="flex items-center gap-2 shrink-0"> 627 <span class="inline-flex items-center gap-1" title="J'aime"> 628 <svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24"> 629 <path d="M12 21s-7-4.35-9.5-8.5C.7 9.4 2.6 5 6.5 5 8.6 5 10.4 6 12 7.5 13.6 6 15.4 5 17.5 5c3.9 0 5.8 4.4 4 7.5C19 16.65 12 21 12 21z"/> 630 </svg> 631 0 632 </span> 633 <span class="inline-flex items-center gap-1" title="Consultations"> 634 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 635 <path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"/> 636 <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> 637 </svg> 638 397 639 </span> 640 <span class="inline-flex items-center gap-1" title="Commentaires"> 641 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 642 <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8-1.34 0-2.61-.26-3.76-.72L3 20l1.72-4.24C4.26 14.61 4 13.34 4 12c0-4.418 4.03-8 9-8s8 3.582 8 8z"/> 643 </svg> 644 0 645 </span> 646 <span>04/07/2026</span> 647 </span> 648 </div> 649 </div> 650</a> 651 </div> 652 653 654 655 <div class="snap-start shrink-0 w-[85%] sm:w-[45%] lg:w-[31%]"> 656 657<a href="/projects/salon-de-jardin" 658 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl overflow-hidden shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 659 <div class="aspect-[16/10] bg-slate-100 dark:bg-slate-800 overflow-hidden"> 660 661 <img src="/uploads/project_covers/91f8c66dd9b84cc8afd587c1c2c3273c.jpg" 662 alt="" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"> 663 664 </div> 665 <div class="p-4"> 666 <h2 class="font-semibold text-slate-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 line-clamp-2"> 667 Salon de jardin 668 669 </h2> 670 671 <div class="mt-3 flex flex-wrap gap-1.5"> 672 673 674 <span class="text-xs px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300" title="FabLab">ð Mobilab 66</span> 675 676 </div> 677 <div class="mt-3 text-xs text-slate-500 dark:text-slate-500 flex items-center justify-between"> 678 <span class="truncate">par Pierre</span> 679 <span class="flex items-center gap-2 shrink-0"> 680 <span class="inline-flex items-center gap-1" title="J'aime"> 681 <svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24"> 682 <path d="M12 21s-7-4.35-9.5-8.5C.7 9.4 2.6 5 6.5 5 8.6 5 10.4 6 12 7.5 13.6 6 15.4 5 17.5 5c3.9 0 5.8 4.4 4 7.5C19 16.65 12 21 12 21z"/> 683 </svg> 684 0 685 </span> 686 <span class="inline-flex items-center gap-1" title="Consultations"> 687 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 688 <path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"/> 689 <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> 690 </svg> 691 332 692 </span> 693 <span class="inline-flex items-center gap-1" title="Commentaires"> 694 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 695 <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8-1.34 0-2.61-.26-3.76-.72L3 20l1.72-4.24C4.26 14.61 4 13.34 4 12c0-4.418 4.03-8 9-8s8 3.582 8 8z"/> 696 </svg> 697 0 698 </span>
699 <span>10/12/2025</span> 700 </span> 701 </div> 702 </div> 703</a> 704 </div> 705 706 707 708 <div class="snap-start shrink-0 w-[85%] sm:w-[45%] lg:w-[31%]"> 709 710<a href="/projects/logo-aristide-maillol-bi-couleur" 711 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl overflow-hidden shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 712 <div class="aspect-[16/10] bg-slate-100 dark:bg-slate-800 overflow-hidden"> 713 714 <img src="/uploads/project_covers/139178da2db641b1ba6505db4ed26651.png" 715 alt="" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"> 716 717 </div> 718 <div class="p-4"> 719 <h2 class="font-semibold text-slate-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 line-clamp-2"> 720 Logo Aristide Maillol (bi couleur) 721 722 </h2> 723 724 <div class="mt-3 flex flex-wrap gap-1.5"> 725 726 727 <span class="text-xs px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300" title="FabLab">ð FabLab Maillol</span> 728 729 </div> 730 <div class="mt-3 text-xs text-slate-500 dark:text-slate-500 flex items-center justify-between"> 731 <span class="truncate">par Dewey Satre</span> 732 <span class="flex items-center gap-2 shrink-0"> 733 <span class="inline-flex items-center gap-1" title="J'aime"> 734 <svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24"> 735 <path d="M12 21s-7-4.35-9.5-8.5C.7 9.4 2.6 5 6.5 5 8.6 5 10.4 6 12 7.5 13.6 6 15.4 5 17.5 5c3.9 0 5.8 4.4 4 7.5C19 16.65 12 21 12 21z"/> 736 </svg> 737 0 738 </span> 739 <span class="inline-flex items-center gap-1" title="Consultations"> 740 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 741 <path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"/> 742 <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> 743 </svg> 744 384 745 </span> 746 <span class="inline-flex items-center gap-1" title="Commentaires"> 747 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 748 <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8-1.34 0-2.61-.26-3.76-.72L3 20l1.72-4.24C4.26 14.61 4 13.34 4 12c0-4.418 4.03-8 9-8s8 3.582 8 8z"/> 749 </svg> 750 0 751 </span> 752 <span>09/12/2025</span> 753 </span> 754 </div> 755 </div> 756</a> 757 </div> 758 759 760 761 <div class="snap-start shrink-0 w-[85%] sm:w-[45%] lg:w-[31%]"> 762 763<a href="/projects/bracelet-ou-porte-cles-connecte-nfc" 764 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl overflow-hidden shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 765 <div class="aspect-[16/10] bg-slate-100 dark:bg-slate-800 overflow-hidden"> 766 767 <img src="/uploads/project_covers/acc827f1dc09495585ac77cf85aeab49.jpeg" 768 alt="" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"> 769 770 </div> 771 <div class="p-4"> 772 <h2 class="font-semibold text-slate-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 line-clamp-2"> 773 Bracelet ou porte-clés connecté NFC 774 775 </h2> 776 777 <div class="mt-3 flex flex-wrap gap-1.5"> 778 779 780 <span class="text-xs px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300" title="FabLab">ð Mobilab 66</span> 781 782 </div> 783 <div class="mt-3 text-xs text-slate-500 dark:text-slate-500 flex items-center justify-between">
784 <span class="truncate">par Fabien</span> 785 <span class="flex items-center gap-2 shrink-0"> 786 <span class="inline-flex items-center gap-1" title="J'aime"> 787 <svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24"> 788 <path d="M12 21s-7-4.35-9.5-8.5C.7 9.4 2.6 5 6.5 5 8.6 5 10.4 6 12 7.5 13.6 6 15.4 5 17.5 5c3.9 0 5.8 4.4 4 7.5C19 16.65 12 21 12 21z"/> 789 </svg> 790 0 791 </span> 792 <span class="inline-flex items-center gap-1" title="Consultations"> 793 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 794 <path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"/> 795 <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> 796 </svg> 797 336 798 </span> 799 <span class="inline-flex items-center gap-1" title="Commentaires"> 800 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 801 <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8-1.34 0-2.61-.26-3.76-.72L3 20l1.72-4.24C4.26 14.61 4 13.34 4 12c0-4.418 4.03-8 9-8s8 3.582 8 8z"/> 802 </svg> 803 0 804 </span> 805 <span>06/08/2025</span> 806 </span> 807 </div> 808 </div> 809</a> 810 </div> 811 812 813 814 <div class="snap-start shrink-0 w-[85%] sm:w-[45%] lg:w-[31%]"> 815 816<a href="/projects/capteur-connecte" 817 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl overflow-hidden shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 818 <div class="aspect-[16/10] bg-slate-100 dark:bg-slate-800 overflow-hidden"> 819 820 <img src="/uploads/project_covers/a8c05fada41c4e6c8d7f34bbbf62b7db.jpg" 821 alt="" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"> 822 823 </div> 824 <div class="p-4"> 825 <h2 class="font-semibold text-slate-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 line-clamp-2"> 826 Capteur connecté 827 828 </h2> 829 830 <div class="mt-3 flex flex-wrap gap-1.5"> 831 832 <span class="text-xs px-2 py-0.5 rounded-full bg-brand-50 text-brand-700 dark:bg-brand-900/40 dark:text-brand-300">Capteurs</span> 833 834 <span class="text-xs px-2 py-0.5 rounded-full bg-brand-50 text-brand-700 dark:bg-brand-900/40 dark:text-brand-300">MicroContrôleur Esp</span> 835 836 837 <span class="text-xs px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300" title="FabLab">ð Mobilab 66</span> 838 839 </div> 840 <div class="mt-3 text-xs text-slate-500 dark:text-slate-500 flex items-center justify-between"> 841 <span class="truncate">par Fabien</span> 842 <span class="flex items-center gap-2 shrink-0"> 843 <span class="inline-flex items-center gap-1" title="J'aime"> 844 <svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24"> 845 <path d="M12 21s-7-4.35-9.5-8.5C.7 9.4 2.6 5 6.5 5 8.6 5 10.4 6 12 7.5 13.6 6 15.4 5 17.5 5c3.9 0 5.8 4.4 4 7.5C19 16.65 12 21 12 21z"/> 846 </svg> 847 0 848 </span> 849 <span class="inline-flex items-center gap-1" title="Consultations"> 850 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 851 <path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"/> 852 <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> 853 </svg> 854 324 855 </span>
856 <span class="inline-flex items-center gap-1" title="Commentaires"> 857 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 858 <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8-1.34 0-2.61-.26-3.76-.72L3 20l1.72-4.24C4.26 14.61 4 13.34 4 12c0-4.418 4.03-8 9-8s8 3.582 8 8z"/> 859 </svg> 860 0 861 </span> 862 <span>27/01/2025</span> 863 </span> 864 </div> 865 </div> 866</a> 867 </div> 868 869 870 871 <div class="snap-start shrink-0 w-[85%] sm:w-[45%] lg:w-[31%]"> 872 873<a href="/projects/support-manche-aspirateur-dyson" 874 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl overflow-hidden shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 875 <div class="aspect-[16/10] bg-slate-100 dark:bg-slate-800 overflow-hidden"> 876 877 <img src="/uploads/project_covers/61538b1974d64c58bfffb876b92d2958.png" 878 alt="" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"> 879 880 </div> 881 <div class="p-4"> 882 <h2 class="font-semibold text-slate-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 line-clamp-2"> 883 Support manche aspirateur Dyson 884 885 </h2> 886 887 <div class="mt-3 flex flex-wrap gap-1.5"> 888 889 890 <span class="text-xs px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300" title="FabLab">ð Mobilab 66</span> 891 892 </div> 893 <div class="mt-3 text-xs text-slate-500 dark:text-slate-500 flex items-center justify-between"> 894 <span class="truncate">par Pierre</span> 895 <span class="flex items-center gap-2 shrink-0"> 896 <span class="inline-flex items-center gap-1" title="J'aime"> 897 <svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24"> 898 <path d="M12 21s-7-4.35-9.5-8.5C.7 9.4 2.6 5 6.5 5 8.6 5 10.4 6 12 7.5 13.6 6 15.4 5 17.5 5c3.9 0 5.8 4.4 4 7.5C19 16.65 12 21 12 21z"/> 899 </svg> 900 0 901 </span> 902 <span class="inline-flex items-center gap-1" title="Consultations"> 903 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 904 <path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"/> 905 <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> 906 </svg> 907 327 908 </span> 909 <span class="inline-flex items-center gap-1" title="Commentaires"> 910 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 911 <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8-1.34 0-2.61-.26-3.76-.72L3 20l1.72-4.24C4.26 14.61 4 13.34 4 12c0-4.418 4.03-8 9-8s8 3.582 8 8z"/> 912 </svg> 913 0 914 </span> 915 <span>10/01/2025</span> 916 </span> 917 </div> 918 </div> 919</a> 920 </div> 921 922 923 924 <div class="snap-start shrink-0 w-[85%] sm:w-[45%] lg:w-[31%]"> 925 926<a href="/projects/la-bouee" 927 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl overflow-hidden shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 928 <div class="aspect-[16/10] bg-slate-100 dark:bg-slate-800 overflow-hidden"> 929 930 <img src="/uploads/project_covers/6f74dfaddfa44d7c8ee10256e6967564.png" 931 alt="" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"> 932 933 </div> 934 <div class="p-4"> 935 <h2 class="font-semibold text-slate-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 line-clamp-2"> 936 La bouée 937 938 </h2> 939 940 <div class="mt-3 flex flex-wrap gap-1.5"> 941 942 943 </div> 944 <div class="mt-3 text-xs text-slate-500 dark:text-slate-500 flex items-center justify-between">
945 <span class="truncate">par Pierre</span> 946 <span class="flex items-center gap-2 shrink-0"> 947 <span class="inline-flex items-center gap-1" title="J'aime"> 948 <svg class="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24"> 949 <path d="M12 21s-7-4.35-9.5-8.5C.7 9.4 2.6 5 6.5 5 8.6 5 10.4 6 12 7.5 13.6 6 15.4 5 17.5 5c3.9 0 5.8 4.4 4 7.5C19 16.65 12 21 12 21z"/> 950 </svg> 951 0 952 </span> 953 <span class="inline-flex items-center gap-1" title="Consultations"> 954 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 955 <path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"/> 956 <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/> 957 </svg> 958 338 959 </span> 960 <span class="inline-flex items-center gap-1" title="Commentaires"> 961 <svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"> 962 <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8-1.34 0-2.61-.26-3.76-.72L3 20l1.72-4.24C4.26 14.61 4 13.34 4 12c0-4.418 4.03-8 9-8s8 3.582 8 8z"/> 963 </svg> 964 0 965 </span> 966 <span>02/12/2024</span> 967 </span> 968 </div> 969 </div> 970</a> 971 </div> 972 973 974 </div> 975 </div> 976 </section> 977 978
978<script> 979 (function () { 980 document.querySelectorAll('[data-carousel]').forEach(function (root) { 981 var track = root.querySelector('[data-carousel-track]'); 982 var prev = root.querySelector('[data-carousel-prev]'); 983 var next = root.querySelector('[data-carousel-next]'); 984 if (!track) return; 985 function step() { 986 var first = track.querySelector(':scope > div'); 987 return first ? first.getBoundingClientRect().width + 20 : track.clientWidth * 0.9; 988 } 989 if (prev) prev.addEventListener('click', function () { track.scrollBy({ left: -step(), behavior: 'smooth' }); }); 990 if (next) next.addEventListener('click', function () { track.scrollBy({ left: step(), behavior: 'smooth' }); }); 991 }); 992 })(); 993 </script>
993 994 995 996 997 998 <section class="bg-slate-50 dark:bg-slate-950 border-y border-slate-200 dark:border-slate-800"> 999 <div class="max-w-6xl mx-auto px-4 py-12"> 1000 <div class="flex items-end justify-between mb-6 gap-3 flex-wrap"> 1001 <div> 1002 <h2 class="text-2xl font-bold text-slate-900 dark:text-white">Communautés</h2> 1003 <p class="text-sm text-slate-500 dark:text-slate-400 mt-1">FabLabs, tiers-lieux et collectifs près de chez vous.</p> 1004 </div> 1005 <a href="/communities/" 1006 class="text-sm text-brand-600 dark:text-brand-400 hover:underline">Toutes les communautés â</a> 1007 </div> 1008 <div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4"> 1009 1010 <a href="/communities/low-tech-lab-66" 1011 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl p-4 shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 1012 <div class="flex items-center gap-3"> 1013 1014 <img src="/uploads/communities/9b86689a2e23429288ca5ac637ef69e0.jpg" 1015 alt="" class="w-12 h-12 rounded-lg object-cover"> 1016 1017 <div class="min-w-0 flex-1"> 1018 <div class="font-semibold text-slate-900 dark:text-white truncate group-hover:text-brand-600 dark:group-hover:text-brand-400">Low-Tech Lab 66</div> 1019 <div class="text-xs text-slate-500 dark:text-slate-400">Association</div> 1020 </div> 1021 </div> 1022 1023 <div class="mt-2 text-xs text-slate-500 dark:text-slate-400">ð 133 chemin du Pas de la Paille, 66000 Perpignan</div> 1024 1025 <div class="mt-2 text-xs text-slate-500 dark:text-slate-400"> 1026 0 projets 1027 </div> 1028 </a> 1029 1030 <a href="/communities/la-cyber-fabrique" 1031 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl p-4 shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 1032 <div class="flex items-center gap-3"> 1033 1034 <img src="/uploads/communities/ce69554ac4de4b2fab5e4e14c44ffc8b.png" 1035 alt="" class="w-12 h-12 rounded-lg object-cover"> 1036 1037 <div class="min-w-0 flex-1"> 1038 <div class="font-semibold text-slate-900 dark:text-white truncate group-hover:text-brand-600 dark:group-hover:text-brand-400">La Cyber Fabrique</div> 1039 <div class="text-xs text-slate-500 dark:text-slate-400">FabLab</div> 1040 </div> 1041 </div> 1042 1043 <div class="mt-2 text-xs text-slate-500 dark:text-slate-400">ð 38 Route de Toulouges, 66270 Le Soler</div> 1044 1045 <div class="mt-2 text-xs text-slate-500 dark:text-slate-400"> 1046 4 projets 1047 </div> 1048 </a> 1049 1050 <a href="/communities/fablab-maillol" 1051 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl p-4 shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 1052 <div class="flex items-center gap-3"> 1053 1054 <img src="/uploads/communities/c7c9edd3b2964992a3f8715be79ce458.jpg" 1055 alt="" class="w-12 h-12 rounded-lg object-cover"> 1056 1057 <div class="min-w-0 flex-1"> 1058 <div class="font-semibold text-slate-900 dark:text-white truncate group-hover:text-brand-600 dark:group-hover:text-brand-400">FabLab Maillol</div> 1059 <div class="text-xs text-slate-500 dark:text-slate-400">FabLab</div> 1060 </div> 1061 </div> 1062 1063 <div class="mt-2 text-xs text-slate-500 dark:text-slate-400">ð Perpignan</div> 1064 1065 <div class="mt-2 text-xs text-slate-500 dark:text-slate-400"> 1066 5 projets 1067 </div> 1068 </a> 1069 1070 <a href="/communities/mobilab-66" 1071 class="group block bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl p-4 shadow-sm hover:shadow-md hover:border-brand-300 dark:hover:border-brand-700 transition"> 1072 <div class="flex items-center gap-3"> 1073 1074 <img src="/uploads/communities/5a7148f36b484f81a9801271934410ca.jpg" 1075 alt="" class="w-12 h-12 rounded-lg object-cover"> 1076 1077 <div class="min-w-0 flex-1"> 1078 <div class="font-semibold text-slate-900 dark:text-white truncate group-hover:text-brand-600 dark:group-hover:text-brand-400">Mobilab 66</div> 1079 <div class="text-xs text-slate-500 dark:text-slate-400">FabLab</div> 1080 </div> 1081 </div> 1082 1083 <div class="mt-2 text-xs text-slate-500 dark:text-slate-400">ð Perpignan</div> 1084 1085 <div class="mt-2 text-xs text-slate-500 dark:text-slate-400"> 1086 29 projets 1087 </div> 1088 </a> 1089 1090 </div> 1091 </div> 1092 </section> 1093 1094 1095 1096 1097 1098 1099 1100 <section class="max-w-6xl mx-auto px-4 py-12"> 1101 <div class="flex items-end justify-between mb-6 gap-3 flex-wrap"> 1102 <div> 1103 <h2 class="text-2xl font-bold text-slate-900 dark:text-white">Derniers messages</h2> 1104 <p class="text-sm text-slate-500 dark:text-slate-400 mt-1">Annonces, discussions et idées de la communauté makers.</p> 1105 </div> 1106 <a href="/posts/" 1107 class="text-sm text-brand-600 dark:text-brand-400 hover:underline">Voir le feed complet â</a> 1108 </div> 1109 <div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3"> 1110 1111 <div class="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl overflow-hidden shadow-sm"> 1112 1113 <a href="/posts/2/"> 1114 <img src="/uploads/post_images/d39a5be33b2546f2b3be71d5f5ef9631.jpg" 1115 alt="" class="w-full h-36 object-cover"> 1116 </a> 1117 1118 <div class="p-4 flex flex-col gap-2"> 1119 <div class="flex items-center gap-2"> 1120 <a href="/u/fabien" class="shrink-0"> 1121 1122 <div class="w-7 h-7 rounded-full bg-slate-200 dark:bg-slate-700 grid place-items-center text-xs font-bold text-slate-500 dark:text-slate-300"> 1123 F 1124 </div> 1125 1126 </a> 1127 <a href="/u/fabien" 1128 class="text-sm font-medium text-slate-800 dark:text-slate-100 hover:text-brand-600 dark:hover:text-brand-400 truncate"> 1129 Fabien 1130 </a> 1131 1132 </div> 1133 <a href="/posts/2/" 1134 class="text-sm text-slate-700 dark:text-slate-300 line-clamp-3 hover:text-slate-900 dark:hover:text-white whitespace-pre-line">Lancement de la nouvelle plateforme FabLab66 pour fédérer tous les tiers-l
1134ieux du département, pour faire ensemble ! 1135Vous pouvez utiliser ce Feed pour partager des news, des questions, des remarques, ... 1136Si vous souhaitez de nouvelles fonctionnalités, si vous rencontrez des bugs, n'hésitez pas à commenter ce message.</a> 1137 <a href="/posts/2/#comments" 1138 class="text-xs text-slate-400 dark:text-slate-500 hover:text-brand-600 dark:hover:text-brand-400"> 1139 2 commentaires 1140 </a> 1141 </div> 1142 </div> 1143 1144 </div> 1145 </section> 1146 1147 1148 1149 <section class="bg-slate-50 dark:bg-slate-950 border-t border-slate-200 dark:border-slate-800"> 1150 <div class="max-w-5xl mx-auto px-4 py-14 grid gap-6 sm:grid-cols-3"> 1151 1152 <div class="bg-white rounded-2xl border border-slate-200 p-5 shadow-sm 1153 dark:bg-slate-900 dark:border-slate-800"> 1154 <div class="text-3xl">ð</div> 1155 <h3 class="mt-3 font-semibold text-slate-900 dark:text-white">Projets documentés</h3> 1156 <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">Rédigez pas-à -pas avec photos, plans, fichiers CAO, code, PDFâ¦</p> 1157 </div> 1158 1159 <div class="bg-white rounded-2xl border border-slate-200 p-5 shadow-sm 1160 dark:bg-slate-900 dark:border-slate-800"> 1161 <div class="text-3xl">ð ï¸</div> 1162 <h3 class="mt-3 font-semibold text-slate-900 dark:text-white">Matériel partagé</h3> 1163 <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">Proposez l'accès à vos machines. Gratuit ou payant, à l'heure ou à la journée.</p> 1164 </div> 1165 1166 <div class="bg-white rounded-2xl border border-slate-200 p-5 shadow-sm 1167 dark:bg-slate-900 dark:border-slate-800"> 1168 <div class="text-3xl">ð</div> 1169 <h3 class="mt-3 font-semibold text-slate-900 dark:text-white">Formations & ateliers</h3> 1170 <p class="mt-1 text-sm text-slate-600 dark:text-slate-400">Trouvez ou proposez des sessions près de chez vous.</p> 1171 </div> 1172 1173 </div> 1174 </section> 1175 1176 </main> 1177 1178 1179 <div id="lightbox" 1180 class="hidden fixed inset-0 z-50 bg-black/90 items-center justify-center p-4 cursor-zoom-out" 1181 role="dialog" aria-modal="true" aria-label="Image en plein écran"> 1182 <button type="button" id="lightbox-close" 1183 class="absolute top-4 right-4 text-white/80 hover:text-white text-3xl leading-none w-10 h-10 flex items-center justify-center rounded-full bg-black/40 hover:bg-black/60" 1184 aria-label="Fermer">×</button> 1185 <img id="lightbox-img" src="" alt="" 1186 class="max-w-[95vw] max-h-[95vh] object-contain rounded-lg shadow-2xl"> 1187 </div> 1188 1189 <footer class="border-t border-slate-200 bg-white dark:bg-slate-900 dark:border-slate-800"> 1190 <div class="max-w-5xl mx-auto px-4 py-6 text-sm text-slate-500 dark:text-slate-400 flex flex-col sm:flex-row justify-between gap-2"> 1191 <div>© 2026 FabLab66 â Communauté des makers des Pyrénées-Orientales</div> 1192 <div class="flex gap-4"> 1193 <a href="/mentions-legales" class="hover:text-brand-500">Mentions légales</a> 1194 <a href="/contact" class="hover:text-brand-500">Contact</a> 1195 </div> 1196 </div> 1197 </footer> 1198 1199 1200
1200<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cropper.min.js"></script>
1200 1201 1202 1203 <div id="crop-modal" 1204 class="hidden fixed inset-0 z-[60] bg-black/80 flex items-center justify-center p-4" 1205 role="dialog" aria-modal="true" aria-label="Recadrer l'image"> 1206 <div class="bg-white dark:bg-slate-900 rounded-2xl shadow-2xl w-full max-w-2xl p-5 space-y-4"> 1207 <div class="flex items-center justify-between"> 1208 <h3 class="font-semibold text-slate-900 dark:text-white">Recadrer l'image</h3> 1209 <button id="crop-cancel" type="button" 1210 class="text-slate-400 hover:text-slate-600 dark:hover:text-slate-300 p-1 rounded" 1211 aria-label="Annuler"> 1212 <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"> 1213 <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/> 1214 </svg> 1215 </button> 1216 </div> 1217 <div class="rounded-lg overflow-hidden bg-slate-100 dark:bg-slate-800 max-h-[55vh]"> 1218 <img id="crop-image" src="" alt="" style="display:block;max-width:100%"> 1219 </div> 1220 <p class="text-xs text-slate-500 dark:text-slate-400">Déplacez et redimensionnez la zone pour choisir le cadrage.</p> 1221 <div class="flex flex-wrap items-center gap-3"> 1222 <span class="text-xs text-slate-500 dark:text-slate-400 shrink-0">Fond :</span> 1223 <div class="flex items-center gap-1.5" id="crop-bg-presets"> 1224 <button type="button" data-bg="transparent" 1225 class="crop-bg-btn w-6 h-6 rounded border-2 border-brand-500 ring-1 ring-brand-400" 1226 style="background:repeating-conic-gradient(#ccc 0% 25%,#fff 0% 50%) 0 0/8px 8px" 1227 title="Transparent"></button> 1228 <button type="button" data-bg="#ffffff" 1229 class="crop-bg-btn w-6 h-6 rounded border-2 border-transparent hover:border-slate-400" 1230 style="background:#ffffff" title="Blanc"></button> 1231 <button type="button" data-bg="#000000" 1232 class="crop-bg-btn w-6 h-6 rounded border-2 border-transparent hover:border-slate-400" 1233 style="background:#000000" title="Noir"></button> 1234 <button type="button" data-bg="#f1f5f9" 1235 class="crop-bg-btn w-6 h-6 rounded border-2 border-transparent hover:border-slate-400" 1236 style="background:#f1f5f9" title="Gris clair"></button> 1237 <label class="w-6 h-6 rounded border-2 border-transparent hover:border-slate-400 overflow-hidden cursor-pointer" title="Couleur personnalisée"> 1238 <input type="color" id="crop-bg-custom" value="#ffffff" 1239 class="w-8 h-8 -mt-1 -ml-1 cursor-pointer opacity-0 absolute"> 1240 <div id="crop-bg-custom-swatch" class="w-full h-full" style="background:linear-gradient(135deg,red,yellow,lime,cyan,blue,magenta)"></div> 1241 </label> 1242 </div> 1243 <div class="flex gap-3 ml-auto"> 1244 <button id="crop-cancel-btn" type="button" 1245 class="px-4 py-2 text-sm rounded-lg border border-slate-300 dark:border-slate-700 hover:bg-slate-50 dark:hover:bg-slate-800 text-slate-700 dark:text-slate-300"> 1246 Annuler 1247 </button> 1248 <button id="crop-confirm" type="button" 1249 class="px-5 py-2 text-sm rounded-lg bg-brand-500 hover:bg-brand-600 text-white font-medium"> 1250 Valider le recadrage 1251 </button> 1252 </div> 1253 </div> 1254 </div> 1255 </div> 1256 1257
1257<script> 1258 // Theme toggle 1259 (function () { 1260 var root = document.documentElement; 1261 function apply(theme) { 1262 if (theme === 'dark') root.classList.add('dark'); 1263 else root.classList.remove('dark'); 1264 } 1265 window.__setTheme = function (mode) { 1266 // mode = 'light' | 'dark' | 'system' 1267 if (mode === 'system') { 1268 localStorage.removeItem('theme'); 1269 apply(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); 1270 } else { 1271 localStorage.setItem('theme', mode); 1272 apply(mode); 1273 } 1274 }; 1275 window.__toggleTheme = function () { 1276 var isDark = root.classList.contains('dark'); 1277 window.__setTheme(isDark ? 'light' : 'dark'); 1278 }; 1279 // Follow system changes only when user hasn't chosen manually 1280 window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function (e) { 1281 if (localStorage.getItem('theme') === null) apply(e.matches ? 'dark' : 'light'); 1282 }); 1283 })(); 1284 </script>
1284 1285 1286
1286<script> 1287 // Image cropper â activated on <input type="file" data-crop="RATIO"> 1288 // RATIO: "1" = square, "1.778" = 16/9, absent/empty = free 1289 (function () { 1290 var modal = document.getElementById('crop-modal'); 1291 var imgEl = document.getElementById('crop-image'); 1292 var confirmBtn = document.getElementById('crop-confirm'); 1293 var cancelBtns = [document.getElementById('crop-cancel'), document.getElementById('crop-cancel-btn')]; 1294 if (!modal || !imgEl) return; 1295 1296 var cropper = null; 1297 var targetInput = null; 1298 var originalFile = null; 1299 var bgColor = 'transparent'; 1300 1301 // Background color presets 1302 var bgBtns = document.querySelectorAll('.crop-bg-btn'); 1303 var customPicker = document.getElementById('crop-bg-custom'); 1304 var customSwatch = document.getElementById('crop-bg-custom-swatch'); 1305 1306 function selectBg(color, activateBtn) { 1307 bgColor = color; 1308 bgBtns.forEach(function (b) { b.classList.remove('border-brand-500', 'ring-1', 'ring-brand-400'); b.classList.add('border-transparent'); }); 1309 if (activateBtn) { activateBtn.classList.remove('border-transparent'); activateBtn.classList.add('border-brand-500', 'ring-1', 'ring-brand-400'); } 1310 } 1311 1312 bgBtns.forEach(function (btn) { 1313 btn.addEventListener('click', function () { selectBg(btn.dataset.bg, btn); }); 1314 }); 1315 if (customPicker) { 1316 customPicker.addEventListener('input', function () { 1317 var color = customPicker.value; 1318 customSwatch.style.background = color; 1319 selectBg(color, null); 1320 }); 1321 } 1322 1323 function openCropper(input, file) { 1324 targetInput = input; 1325 originalFile = file; 1326 var reader = new FileReader(); 1327 reader.onload = function (e) { 1328 if (cropper) { cropper.destroy(); cropper = null; } 1329 imgEl.src = e.target.result; 1330 modal.classList.remove('hidden'); 1331 document.body.style.overflow = 'hidden'; 1332 var ratioStr = input.dataset.crop; 1333 var ratio = parseFloat(ratioStr); 1334 cropper = new Cropper(imgEl, { 1335 aspectRatio: (ratioStr && !isNaN(ratio)) ? ratio : NaN, 1336 viewMode: 1, 1337 autoCropArea: 0.9, 1338 responsive: true, 1339 guides: true, 1340 center: true, 1341 highlight: false, 1342 }); 1343 }; 1344 reader.readAsDataURL(file); 1345 } 1346 1347 function closeCropper(clearInput) { 1348 modal.classList.add('hidden'); 1349 document.body.style.overflow = ''; 1350 if (cropper) { cropper.destroy(); cropper = null; } 1351 imgEl.src = ''; 1352 if (clearInput && targetInput) targetInput.value = ''; 1353 targetInput = null; 1354 originalFile = null; 1355 } 1356 1357 cancelBtns.forEach(function (btn) { 1358 if (btn) btn.addEventListener('click', function () { closeCropper(true); }); 1359 }); 1360 1361 confirmBtn.addEventListener('click', function () { 1362 if (!cropper || !targetInput) return; 1363 var isPng = (originalFile && originalFile.type === 'image/png') && bgColor === 'transparent'; 1364 var mime = isPng ? 'image/png' : 'image/jpeg'; 1365 var ext = isPng ? 'png' : 'jpg'; 1366 var canvasOpts = { maxWidth: 2048, maxHeight: 2048, imageSmoothingEnabled: true, imageSmoothingQuality: 'high' }; 1367 if (bgColor && bgColor !== 'transparent') canvasOpts.fillColor = bgColor; 1368 var canvas = cropper.getCroppedCanvas(canvasOpts); 1369 canvas.toBlob(function (blob) { 1370 var newFile = new File([blob], 'crop.' + ext, { type: mime }); 1371 try { 1372 var dt = new DataTransfer(); 1373 dt.items.add(newFile); 1374 targetInput.files = dt.files; 1375 } catch (_) { 1376 // DataTransfer not supported â fallback: keep original file 1377 } 1378 closeCropper(false); 1379 }, mime, 0.92); 1380 }); 1381 1382 // Watch ALL file inputs (present + future via delegation) 1383 document.addEventListener('change', function (e) { 1384 var input = e.target; 1385 if (!input || input.tagName !== 'INPUT' || input.type !== 'file') return; 1386 if (!('crop' in input.dataset)) return; 1387 if (!input.files || !input.files[0]) return; 1388 if (!window.Cropper) return; 1389 var file = input.files[0]; 1390 if (!file.type.startsWith('image/')) return; 1391 openCropper(input, file); 1392 }); 1393 })(); 1394 </script>
1394 1395 1396
1396<script> 1397 // Syntax highlighting for markdown code blocks. 1398 window.addEventListener('DOMContentLoaded', function () { 1399 if (window.hljs) { 1400 document.querySelectorAll('.prose pre code').forEach(function (el) { 1401 try { window.hljs.highlightElement(el); } catch (_) {} 1402 }); 1403 } 1404 }); 1405 1406 // Voice dictation â Web Speech API on <textarea data-voice="1"> 1407 (function () { 1408 var SR = window.SpeechRecognition || window.webkitSpeechRecognition; 1409 if (!SR) return; 1410 1411 function attach(ta) { 1412 if (ta.dataset.voiceReady) return; 1413 ta.dataset.voiceReady = '1'; 1414 1415 var wrapper = document.createElement('div'); 1416 wrapper.className = 'relative'; 1417 ta.parentNode.insertBefore(wrapper, ta); 1418 wrapper.appendChild(ta); 1419 1420 var btn = document.createElement('button'); 1421 btn.type = 'button'; 1422 btn.setAttribute('aria-label', 'Dictée vocale'); 1423 btn.title = 'Dictée vocale (cliquer pour démarrer / arrêter)'; 1424 btn.className = 'absolute top-2 right-2 z-10 w-8 h-8 rounded-full bg-white/90 dark:bg-slate-800/90 border border-slate-300 dark:border-slate-600 shadow-sm hover:bg-brand-50 dark:hover:bg-slate-700 text-slate-500 dark:text-slate-300 flex items-center justify-center transition'; 1425 btn.innerHTML = '<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75"><path stroke-linecap="round" stroke-linejoin="round" d="M12 18.75a6 6 0 006-6v-1.5m-6 7.5a6 6 0 01-6-6v-1.5m6 7.5v3.75m-3.75 0h7.5M12 15.75a3 3 0 01-3-3V4.5a3 3 0 116 0v8.25a3 3 0 01-3 3z"/></svg>'; 1426 wrapper.appendChild(btn); 1427 1428 var rec = null; 1429 var active = false; 1430 1431 function insertText(text) { 1432 if (!text) return; 1433 var start = ta.selectionStart || ta.value.length; 1434 var end = ta.selectionEnd || ta.value.length; 1435 var before = ta.value.slice(0, start); 1436 var after = ta.value.slice(end); 1437 var sep = (before && !/\s$/.test(before)) ? ' ' : ''; 1438 ta.value = before + sep + text + after; 1439 var pos = (before + sep + text).length; 1440 ta.setSelectionRange(pos, pos); 1441 ta.dispatchEvent(new Event('input', { bubbles: true })); 1442 } 1443 1444 function stop() { 1445 if (rec) { try { rec.stop(); } catch (_) {} } 1446 active = false; 1447 btn.classList.remove('bg-red-500', 'text-white', 'animate-pulse'); 1448 btn.classList.add('bg-white/90', 'dark:bg-slate-800/90', 'text-slate-500', 'dark:text-slate-300'); 1449 } 1450 1451 function start() { 1452 try { 1453 rec = new SR(); 1454 rec.lang = document.documentElement.lang || 'fr-FR'; 1455 if (rec.lang.length === 2) rec.lang = rec.lang + '-FR'; 1456 rec.continuous = true; 1457 rec.interimResults = false; 1458 rec.onresult = function (e) { 1459 var chunk = ''; 1460 for (var i = e.resultIndex; i < e.results.length; i++) { 1461 if (e.results[i].isFinal) chunk += e.results[i][0].transcript; 1462 } 1463 if (chunk) insertText(chunk.trim()); 1464 }; 1465 rec.onerror = function () { stop(); }; 1466 rec.onend = function () { if (active) { try { rec.start(); } catch (_) { stop(); } } }; 1467 rec.start(); 1468 active = true; 1469 btn.classList.remove('bg-white/90', 'dark:bg-slate-800/90', 'text-slate-500', 'dark:text-slate-300'); 1470 btn.classList.add('bg-red-500', 'text-white', 'animate-pulse'); 1471 } catch (_) { stop(); } 1472 } 1473 1474 btn.addEventListener('click', function () { 1475 if (active) stop(); else start(); 1476 }); 1477 } 1478 1479 function scan(root) { 1480 (root || document).querySelectorAll('textarea[data-voice="1"]').forEach(attach); 1481 } 1482 window.addEventListener('DOMContentLoaded', function () { scan(document); }); 1483 document.addEventListener('htmx:afterSwap', function (e) { scan(e.target); }); 1484 })(); 1485 1486 // In-page image lightbox. 1487 (function () { 1488 var box = document.getElementById('lightbox'); 1489 var img = document.getElementById('lightbox-img'); 1490 var closer = document.getElementById('lightbox-close'); 1491 if (!box || !img) return; 1492 1493 function open(src, alt) { 1494 img.src = src; 1495 img.alt = alt || ''; 1496 box.classList.remove('hidden'); 1497 box.classList.add('flex'); 1498 document.body.style.overflow = 'hidden'; 1499 } 1500 function close() { 1501 box.classList.add('hidden'); 1502 box.classList.remove('flex'); 1503 img.src = ''; 1504 document.body.style.overflow = ''; 1505 } 1506 1507 // Any image marked data-lightbox, plus any <img> inside a .prose block, 1508 // opens the overlay instead of navigating away. 1509 document.addEventListener('click', function (e) { 1510 var el = e.target; 1511 if (!el) return; 1512 1513 // Trigger by wrapping anchor with data-lightbox-src 1514 var trigger = el.closest && el.closest('[data-lightbox-src]'); 1515 if (trigger) { 1516 e.preventDefault(); 1517 open(trigger.getAttribute('data-lightbox-src'), trigger.getAttribute('data-lightbox-alt')); 1518 return; 1519 } 1520 1521 // Trigger by clicking any img inside a .prose block 1522 if (el.tagName === 'IMG' && el.closest('.prose')) { 1523 e.preventDefault(); 1524 open(el.currentSrc || el.src, el.alt); 1525 return; 1526 } 1527 }); 1528 1529 box.addEventListener('click', function (e) { 1530 if (e.target === box || e.target === closer) close(); 1531 }); 1532 document.addEventListener('keydown', function (e) { 1533 if (e.key === 'Escape' && !box.classList.contains('hidden')) close(); 1534 }); 1535 })(); 1536 </script>
1536 1537 1538</body> 1539</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.