TypeScript 50.6%
JavaScript 46.1%
SQL 2.1%
Shell 0.6%
CSS 0.5%
1"use client";2import { useState } from "react";3import { IconChevron } from "./icons";45export function Gallery({ images, credit }: { images: string[]; credit: string }) {6 const [i, setI] = useState(0); const [bad, setBad] = useState<Set<number>>(new Set());7 const imgs = images.filter((_, k) => !bad.has(k));8 if (!imgs.length) return <div className="aspect-[16/10] md:aspect-[21/9] rounded-card bg-surface-2 grid place-items-center text-ink-3 text-sm">Aucune photo disponible pour cette annonce</div>;9 const cur = Math.min(i, imgs.length - 1);10 return (11 <figure className="relative">12 <div className="aspect-[16/10] md:aspect-[21/9] rounded-card overflow-hidden bg-surface-2 relative">13 {/* eslint-disable-next-line @next/next/no-img-element */}14 <img key={imgs[cur]} src={imgs[cur]} alt={`Photo ${cur + 1} sur ${imgs.length}`} className="absolute inset-0 w-full h-full object-cover" referrerPolicy="no-referrer" onError={() => setBad((b) => new Set(b).add(images.indexOf(imgs[cur])))} />15 {imgs.length > 1 && (<>16 <button type="button" onClick={() => setI((cur - 1 + imgs.length) % imgs.length)} className="absolute left-3 top-1/2 -translate-y-1/2 p-2 rounded-full bg-white/90 shadow rotate-180" aria-label="Photo précédente"><IconChevron /></button>17 <button type="button" onClick={() => setI((cur + 1) % imgs.length)} className="absolute right-3 top-1/2 -translate-y-1/2 p-2 rounded-full bg-white/90 shadow" aria-label="Photo suivante"><IconChevron /></button>18 <span className="absolute bottom-3 right-3 tv-badge bg-black/55 text-white">{cur + 1} / {imgs.length}</span>19 </>)}20 </div>21 <figcaption className="mt-1.5 text-[11px] text-ink-3">Photos : {credit} (affichées depuis le site d'origine, droits réservés à leur propriétaire).</figcaption>22 {imgs.length > 1 && (23 <div className="mt-2 flex gap-2 overflow-x-auto no-scrollbar">24 {imgs.slice(0, 12).map((src, k) => (25 // eslint-disable-next-line @next/next/no-img-element26 <button key={src} type="button" onClick={() => setI(k)} className={`shrink-0 w-20 h-14 rounded-sm overflow-hidden border-2 ${k === cur ? "border-brand" : "border-transparent"}`} aria-label={`Voir la photo ${k + 1}`}><img src={src} alt="" className="w-full h-full object-cover" loading="lazy" referrerPolicy="no-referrer" /></button>27 ))}28 </div>29 )}30 </figure>31 );32}33