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
+17 -11
View File
@@ -49,27 +49,33 @@ export function JournalView({
}, []);
if (entries.length === 0) {
return <p className="text-sm text-ink/70">Aucun événement pour l&apos;instant.</p>;
return <p className="text-sm text-marble/60">Aucun décret pour l&apos;instant.</p>;
}
return (
<ol className="flex flex-col gap-2">
{entries.map((entry) => {
const judgePseudo = pseudoById[entry.judge_id] ?? "Un juge";
const targetPseudo = pseudoById[entry.target_id] ?? "un membre";
const judgePseudo = pseudoById[entry.judge_id] ?? "Un Archonte";
const targetPseudo = pseudoById[entry.target_id] ?? "un Citoyen";
const sign = entry.delta > 0 ? `+${entry.delta}` : `${entry.delta}`;
return (
<li
key={entry.id}
className="rounded-lg border border-navy/10 bg-white px-4 py-3 text-sm shadow-sm"
className="marble-surface flex gap-3 rounded-lg border border-gold/25 px-4 py-3 text-sm shadow-sm"
>
<span className="font-medium text-navy">{judgePseudo}</span> a donné{" "}
<span className={entry.delta >= 0 ? "font-semibold text-green-700" : "font-semibold text-red-700"}>
{sign}
</span>{" "}
à <span className="font-medium text-navy">{targetPseudo}</span>
{entry.reason && <span className="text-ink/70"> {entry.reason}</span>}
<div className="mt-1 text-xs text-ink/50">{formatTime(entry.created_at)}</div>
<span
className="mt-1 h-3 w-3 shrink-0 rounded-full bg-oxblood shadow-[0_0_0_2px_rgba(165,52,42,0.25)]"
aria-hidden
/>
<div>
<span className="font-medium text-text-marble">{judgePseudo}</span> a proclamé{" "}
<span className={entry.delta >= 0 ? "font-semibold text-olive" : "font-semibold text-oxblood"}>
{sign}
</span>{" "}
à <span className="font-medium text-text-marble">{targetPseudo}</span>
{entry.reason && <span className="text-text-mut"> {entry.reason}</span>}
<div className="mt-1 text-xs text-text-mut">{formatTime(entry.created_at)}</div>
</div>
</li>
);
})}
+8 -2
View File
@@ -23,8 +23,14 @@ export default async function JournalPage() {
return (
<div className="mx-auto w-full max-w-2xl px-4 py-8">
<h1 className="mb-2 text-2xl font-semibold text-navy">Le crieur</h1>
<p className="mb-6 text-sm text-ink/60">Journal public de toutes les attributions de points.</p>
<div className="mb-6 text-center">
<h1 className="font-heading text-2xl tracking-[0.1em] text-gold-bright uppercase">
Le Crieur
</h1>
<p className="font-serif text-sm text-marble/60 italic">
Le fil des décrets chaque honneur, chaque blâme, proclamé publiquement.
</p>
</div>
<JournalView initialEntries={entries ?? []} pseudoById={pseudoById} />
</div>
);