Design responsive, logo, et correctif RLS upload photo
Design & UX : - Renomme "Administration" en "Admin" (nav, page, docs). - Logo original (marteau de juge stylisé navy/or) en favicon (src/app/icon.svg, remplace le favicon.ico par défaut de create-next-app) et dans la navbar (components/logo.tsx). - Navbar : menu hamburger sur mobile (les liens débordaient à partir de ~4 entrées sur petit écran). - Leaderboard : lignes en deux niveaux sur mobile (infos membre / contrôles juges) au lieu d'un seul flex-wrap qui devenait illisible. - Contrôles de points juges (JudgePointControls) : boutons et champ montant réduits en mode compact pour tenir dans les colonnes du podium sur petit écran. - Podium : scroll horizontal de secours (overflow-x-auto) si le contenu dépasse malgré tout sur très petits écrans. - Table admin : pseudo/avatar sur une ligne, rôle/statut/actions sur une autre en mobile (le flex-1 sur l'input pseudo n'avait aucun effet en layout colonne). Correctif sécurité/fonctionnel : - storage.objects n'avait que des policies INSERT et UPDATE pour le bucket avatars, pas de policy SELECT. Postgres a besoin de lire la ligne existante pour évaluer la clause USING d'un UPDATE : sans SELECT, tout remplacement de photo (upsert) échouait avec "new row violates row-level security policy", même si les policies INSERT/UPDATE étaient correctes. Ajout d'une policy SELECT publique sur le bucket avatars (cohérent avec le fait que le bucket est déjà public en lecture). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -99,20 +99,25 @@ export function LeaderboardView({
|
||||
return (
|
||||
<li
|
||||
key={profile.id}
|
||||
className={`flex flex-wrap items-center gap-3 rounded-lg border border-navy/10 bg-white px-4 py-3 shadow-sm transition-colors ${
|
||||
className={`flex flex-col gap-2 rounded-lg border border-navy/10 bg-white px-4 py-3 shadow-sm transition-colors sm:flex-row sm:items-center sm:gap-3 ${
|
||||
flashingId === profile.id ? "animate-points-flash" : ""
|
||||
}`}
|
||||
>
|
||||
<span className="w-6 shrink-0 text-center font-semibold text-navy/60">
|
||||
{profile.rank}
|
||||
</span>
|
||||
<Avatar pseudo={profile.pseudo} avatarUrl={profile.avatar_url} size="sm" />
|
||||
<span className="flex-1 truncate font-medium">{profile.pseudo}</span>
|
||||
<ProgressBadge direction={progress.direction} amount={progress.amount} />
|
||||
<span className="font-semibold text-navy">{profile.points}</span>
|
||||
{isJudge && (
|
||||
<JudgePointControls memberId={profile.id} onApplyDelta={applyOptimisticDelta} />
|
||||
)}
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="w-6 shrink-0 text-center font-semibold text-navy/60">
|
||||
{profile.rank}
|
||||
</span>
|
||||
<Avatar pseudo={profile.pseudo} avatarUrl={profile.avatar_url} size="sm" />
|
||||
<span className="flex-1 truncate font-medium sm:flex-initial">{profile.pseudo}</span>
|
||||
<ProgressBadge direction={progress.direction} amount={progress.amount} />
|
||||
<span className="font-semibold text-navy sm:hidden">{profile.points}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 sm:ml-auto">
|
||||
<span className="hidden font-semibold text-navy sm:inline">{profile.points}</span>
|
||||
{isJudge && (
|
||||
<JudgePointControls memberId={profile.id} onApplyDelta={applyOptimisticDelta} />
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user