Rend les photos du Mur de la Honte cliquables pour les agrandir
Build and deploy / deploy (push) Successful in 36s
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:
+49
-11
@@ -105,26 +105,31 @@ function NoteCard({
|
|||||||
reactionCounts,
|
reactionCounts,
|
||||||
myReactions,
|
myReactions,
|
||||||
onToggleReaction,
|
onToggleReaction,
|
||||||
|
onImageClick,
|
||||||
}: {
|
}: {
|
||||||
note: WallNoteRow;
|
note: WallNoteRow;
|
||||||
reactionCounts: Record<string, number>;
|
reactionCounts: Record<string, number>;
|
||||||
myReactions: Set<string>;
|
myReactions: Set<string>;
|
||||||
onToggleReaction: (emoji: string) => void;
|
onToggleReaction: (emoji: string) => void;
|
||||||
|
onImageClick: (url: string) => void;
|
||||||
}) {
|
}) {
|
||||||
|
const imageUrl = note.image_url;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="marble-surface flex min-h-[7rem] flex-col justify-between gap-2 rounded-lg border border-gold/30 p-3 shadow-md"
|
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)` }}
|
style={{ transform: `rotate(${rotationFor(note.id)}deg)` }}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
{note.image_url && (
|
{imageUrl && (
|
||||||
<Image
|
<button
|
||||||
src={note.image_url}
|
type="button"
|
||||||
alt=""
|
onClick={() => onImageClick(imageUrl)}
|
||||||
width={300}
|
className="cursor-zoom-in"
|
||||||
height={200}
|
aria-label="Agrandir l'image"
|
||||||
className="max-h-32 w-full rounded-md object-cover"
|
>
|
||||||
/>
|
<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>
|
<p className="text-sm text-text-marble">{note.text}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -165,15 +170,17 @@ export function MurView({
|
|||||||
const [posting, setPosting] = useState(false);
|
const [posting, setPosting] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [historyDateFilter, setHistoryDateFilter] = useState("all");
|
const [historyDateFilter, setHistoryDateFilter] = useState("all");
|
||||||
|
const [zoomedImage, setZoomedImage] = useState<string | null>(null);
|
||||||
|
|
||||||
const refetch = useCallback(async () => {
|
const refetch = useCallback(async () => {
|
||||||
const supabase = createClient();
|
const supabase = createClient();
|
||||||
const [{ data: todayNotes }, { data: myNotes }, { data: hist }, { data: counts }, { data: mine }] =
|
const [{ data: todayNotes }, { data: myNotes }, { data: hist }, { data: counts }, { data: mine }] =
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
supabase.rpc("wall_notes_today"),
|
supabase.rpc("wall_notes_today"),
|
||||||
isJudge
|
// Depuis V14, les Archontes peuvent aussi publier — plus de
|
||||||
? Promise.resolve({ data: null })
|
// filtre par rôle ici non plus (sinon leur note du jour ne se
|
||||||
: supabase
|
// mettait jamais à jour après le chargement initial).
|
||||||
|
supabase
|
||||||
.from("wall_notes")
|
.from("wall_notes")
|
||||||
.select("id, text, image_url, created_at")
|
.select("id, text, image_url, created_at")
|
||||||
.order("created_at", { ascending: false }),
|
.order("created_at", { ascending: false }),
|
||||||
@@ -360,6 +367,7 @@ export function MurView({
|
|||||||
reactionCounts={reactionCounts[note.id] ?? {}}
|
reactionCounts={reactionCounts[note.id] ?? {}}
|
||||||
myReactions={myReactions[note.id] ?? new Set()}
|
myReactions={myReactions[note.id] ?? new Set()}
|
||||||
onToggleReaction={(emoji) => handleToggleReaction(note.id, emoji)}
|
onToggleReaction={(emoji) => handleToggleReaction(note.id, emoji)}
|
||||||
|
onImageClick={setZoomedImage}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -371,6 +379,12 @@ export function MurView({
|
|||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-olive">Ta note d'aujourd'hui est publiée.</p>
|
<p className="text-sm text-olive">Ta note d'aujourd'hui est publiée.</p>
|
||||||
{myNoteToday.image_url && (
|
{myNoteToday.image_url && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setZoomedImage(myNoteToday.image_url)}
|
||||||
|
className="cursor-zoom-in"
|
||||||
|
aria-label="Agrandir l'image"
|
||||||
|
>
|
||||||
<Image
|
<Image
|
||||||
src={myNoteToday.image_url}
|
src={myNoteToday.image_url}
|
||||||
alt=""
|
alt=""
|
||||||
@@ -378,6 +392,7 @@ export function MurView({
|
|||||||
height={200}
|
height={200}
|
||||||
className="mt-2 max-h-40 w-full rounded-md object-cover"
|
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">
|
<p className="mt-2 rounded-md border border-gold/20 bg-white/40 px-3 py-2 text-sm text-text-marble">
|
||||||
{myNoteToday.text}
|
{myNoteToday.text}
|
||||||
@@ -482,6 +497,12 @@ export function MurView({
|
|||||||
</p>
|
</p>
|
||||||
<p className="text-text-marble">{note.text}</p>
|
<p className="text-text-marble">{note.text}</p>
|
||||||
{note.image_url && (
|
{note.image_url && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setZoomedImage(note.image_url)}
|
||||||
|
className="cursor-zoom-in"
|
||||||
|
aria-label="Agrandir l'image"
|
||||||
|
>
|
||||||
<Image
|
<Image
|
||||||
src={note.image_url}
|
src={note.image_url}
|
||||||
alt=""
|
alt=""
|
||||||
@@ -489,6 +510,7 @@ export function MurView({
|
|||||||
height={150}
|
height={150}
|
||||||
className="mt-1 max-h-32 rounded-md object-cover"
|
className="mt-1 max-h-32 rounded-md object-cover"
|
||||||
/>
|
/>
|
||||||
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@@ -497,6 +519,22 @@ export function MurView({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user