Refonte visuelle : direction artistique Grèce antique

Remplace le thème générique (tokens navy/gold/ivory re-thématisables par
édition) par une direction artistique fixe et codée en dur : tribunal
égéen de nuit — marbre, or, mer sombre, sceaux de cire.

Fondations (globals.css, layout.tsx) :
- Polices next/font/google : Cinzel (titres, tracking large), Cormorant
  Garamond (citations italiques), Manrope (interface).
- Nouveaux tokens couleur : ink/ink-2 (fond mer de nuit), marble/marble-2
  (surfaces claires), gold/gold-bright (accents), oxblood (blâmes/erreurs),
  olive (honneurs/succès), sea, text-marble/text-mut (texte sur marbre —
  jamais de doré en texte courant, contraste insuffisant).
- Classes utilitaires : .marble-surface (texture par dégradés, pas
  d'image de bruit), .meander-divider (frise à méandre grecque en SVG
  data-URI).

Composants d'ornement (aucune image bitmap) :
- components/laurel-wreath.tsx : couronne de laurier calculée par
  trigonométrie (deux arcs symétriques de feuilles), réutilisée en logo,
  favicon (icon.svg régénéré avec les mêmes coordonnées) et couronne du
  rang 1 du podium.
- components/diamond-divider.tsx : séparateur ◆ avec filets dégradés.

Header global (components/header.tsx, remplace nav-bar.tsx) :
- Logo laurier + "LE TRIBUNAL" à gauche (cliquable vers le leaderboard).
- Chip utilisateur à droite : avatar (bordure dorée), pseudo, badge de
  rôle (Archonte/Citoyen), points de gloire, menu déroulant (Mon profil,
  Le Conseil des Archontes si juge, Se déconnecter).
- Onglets L'Agora / Le Crieur, frise à méandre en séparateur.
- Responsive : nom du site et pseudo masqués sous le breakpoint sm,
  l'avatar reste toujours visible.

Vocabulaire diégétique (toujours avec le terme fonctionnel à côté) :
juges → Archontes, membres → Citoyens, leaderboard → L'Agora, journal →
Le Crieur (décrets avec sceau de cire oxblood), points positifs/négatifs
→ Honneurs/Blâmes, points → gloires, section admin → Le Conseil des
Archontes.

Avatar : bordure dorée, couleur de fallback dérivée d'un hash du pseudo
(au lieu d'une couleur fixe).

Toutes les pages (login, signup, leaderboard/podium, journal, admin,
profil) sont passées sur les nouveaux tokens/polices/vocabulaire.

README.md et CLAUDE.md : section "Ré-thématisation" remplacée par
"Direction artistique" documentant la palette, les polices et les
ornements ; toute mention du système de re-thème par édition retirée.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Valentin ROBIN
2026-07-12 13:13:54 +02:00
parent e6f4463cb0
commit 9f4e58019b
25 changed files with 541 additions and 291 deletions
+10 -8
View File
@@ -17,13 +17,13 @@ type Profile = {
function ProgressBadge({ direction, amount }: { direction: string; amount: number }) {
if (direction === "up") {
return <span className="text-xs font-semibold text-green-700">{amount}</span>;
return <span className="text-xs font-semibold text-olive">{amount}</span>;
}
if (direction === "down") {
return <span className="text-xs font-semibold text-red-700">{amount}</span>;
return <span className="text-xs font-semibold text-oxblood">{amount}</span>;
}
if (direction === "same") {
return <span className="text-xs text-ink/40">=</span>;
return <span className="text-xs text-text-mut">=</span>;
}
return null;
}
@@ -82,7 +82,7 @@ export function LeaderboardView({
const rest = ranked.filter((p) => p.rank > 3);
if (profiles.length === 0) {
return <p className="text-sm text-ink/70">Personne n&apos;est encore inscrit.</p>;
return <p className="text-sm text-marble/60">Personne n&apos;est encore inscrit.</p>;
}
return (
@@ -99,21 +99,23 @@ export function LeaderboardView({
return (
<li
key={profile.id}
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 ${
className={`marble-surface flex flex-col gap-2 rounded-lg border border-gold/25 px-4 py-3 shadow-sm transition-colors sm:flex-row sm:items-center sm:gap-3 ${
flashingId === profile.id ? "animate-points-flash" : ""
}`}
>
<div className="flex items-center gap-3">
<span className="w-6 shrink-0 text-center font-semibold text-navy/60">
<span className="w-6 shrink-0 text-center font-heading text-text-mut">
{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>
<span className="font-semibold text-text-marble 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>
<span className="hidden font-semibold text-text-marble sm:inline">
{profile.points}
</span>
{isJudge && (
<JudgePointControls memberId={profile.id} onApplyDelta={applyOptimisticDelta} />
)}