Rend les photos du Mur de la Honte cliquables pour les agrandir
Build and deploy / deploy (push) Successful in 36s

Ajoute une visionneuse plein écran (mur du jour, sa propre note, et l'historique complet côté Archontes). Corrige au passage un bug introduit avec l'ouverture du Mur aux Archontes (V14) : leur propre note du jour ne se rafraîchissait jamais après le chargement initial, le refetch la filtrait encore par rôle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Valentin ROBIN
2026-08-25 17:46:19 +02:00
parent ede1d6c74d
commit 4532403c95
+66 -28
View File
@@ -105,26 +105,31 @@ function NoteCard({
reactionCounts,
myReactions,
onToggleReaction,
onImageClick,
}: {
note: WallNoteRow;
reactionCounts: Record<string, number>;
myReactions: Set<string>;
onToggleReaction: (emoji: string) => void;
onImageClick: (url: string) => void;
}) {
const imageUrl = note.image_url;
return (
<div
className="marble-surface flex min-h-[7rem] flex-col justify-between gap-2 rounded-lg border border-gold/30 p-3 shadow-md"
style={{ transform: `rotate(${rotationFor(note.id)}deg)` }}
>
<div className="flex flex-col gap-2">
{note.image_url && (
<Image
src={note.image_url}
alt=""
width={300}
height={200}
className="max-h-32 w-full rounded-md object-cover"
/>
{imageUrl && (
<button
type="button"
onClick={() => onImageClick(imageUrl)}
className="cursor-zoom-in"
aria-label="Agrandir l'image"
>
<Image src={imageUrl} alt="" width={300} height={200} className="max-h-32 w-full rounded-md object-cover" />
</button>
)}
<p className="text-sm text-text-marble">{note.text}</p>
</div>
@@ -165,18 +170,20 @@ export function MurView({
const [posting, setPosting] = useState(false);
const [error, setError] = useState<string | null>(null);
const [historyDateFilter, setHistoryDateFilter] = useState("all");
const [zoomedImage, setZoomedImage] = useState<string | null>(null);
const refetch = useCallback(async () => {
const supabase = createClient();
const [{ data: todayNotes }, { data: myNotes }, { data: hist }, { data: counts }, { data: mine }] =
await Promise.all([
supabase.rpc("wall_notes_today"),
isJudge
? Promise.resolve({ data: null })
: supabase
.from("wall_notes")
.select("id, text, image_url, created_at")
.order("created_at", { ascending: false }),
// Depuis V14, les Archontes peuvent aussi publier — plus de
// filtre par rôle ici non plus (sinon leur note du jour ne se
// mettait jamais à jour après le chargement initial).
supabase
.from("wall_notes")
.select("id, text, image_url, created_at")
.order("created_at", { ascending: false }),
isJudge
? supabase
.from("wall_notes")
@@ -360,6 +367,7 @@ export function MurView({
reactionCounts={reactionCounts[note.id] ?? {}}
myReactions={myReactions[note.id] ?? new Set()}
onToggleReaction={(emoji) => handleToggleReaction(note.id, emoji)}
onImageClick={setZoomedImage}
/>
))}
</div>
@@ -371,13 +379,20 @@ export function MurView({
<div>
<p className="text-sm text-olive">Ta note d&apos;aujourd&apos;hui est publiée.</p>
{myNoteToday.image_url && (
<Image
src={myNoteToday.image_url}
alt=""
width={300}
height={200}
className="mt-2 max-h-40 w-full rounded-md object-cover"
/>
<button
type="button"
onClick={() => setZoomedImage(myNoteToday.image_url)}
className="cursor-zoom-in"
aria-label="Agrandir l'image"
>
<Image
src={myNoteToday.image_url}
alt=""
width={300}
height={200}
className="mt-2 max-h-40 w-full rounded-md object-cover"
/>
</button>
)}
<p className="mt-2 rounded-md border border-gold/20 bg-white/40 px-3 py-2 text-sm text-text-marble">
{myNoteToday.text}
@@ -482,13 +497,20 @@ export function MurView({
</p>
<p className="text-text-marble">{note.text}</p>
{note.image_url && (
<Image
src={note.image_url}
alt=""
width={200}
height={150}
className="mt-1 max-h-32 rounded-md object-cover"
/>
<button
type="button"
onClick={() => setZoomedImage(note.image_url)}
className="cursor-zoom-in"
aria-label="Agrandir l'image"
>
<Image
src={note.image_url}
alt=""
width={200}
height={150}
className="mt-1 max-h-32 rounded-md object-cover"
/>
</button>
)}
</div>
</li>
@@ -497,6 +519,22 @@ export function MurView({
)}
</div>
)}
{zoomedImage && (
<div className="fixed inset-0 z-40 flex items-center justify-center bg-ink/90 p-4 backdrop-blur-sm">
<button
type="button"
onClick={() => setZoomedImage(null)}
className="absolute top-4 right-4 rounded-full bg-ink-2/80 p-2 text-marble transition hover:bg-ink-2"
aria-label="Fermer"
>
<IconClose className="h-5 w-5" />
</button>
<div className="relative h-[80vh] w-full max-w-2xl">
<Image src={zoomedImage} alt="" fill sizes="100vw" className="object-contain" />
</div>
</div>
)}
</div>
);
}