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:
@@ -77,14 +77,14 @@ function MemberRow({ member, isSelf }: { member: Member; isSelf: boolean }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<li className="flex flex-col gap-2 rounded-lg border border-navy/10 bg-white px-4 py-3 shadow-sm sm:flex-row sm:items-center sm:gap-4">
|
||||
<li className="marble-surface flex flex-col gap-2 rounded-lg border border-gold/25 px-4 py-3 shadow-sm sm:flex-row sm:items-center sm:gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Avatar pseudo={member.pseudo} avatarUrl={member.avatar_url} size="sm" />
|
||||
<input
|
||||
type="text"
|
||||
value={pseudo}
|
||||
onChange={(event) => setPseudo(event.target.value)}
|
||||
className="w-full flex-1 rounded-md border border-navy/20 bg-white px-2 py-1 text-sm outline-none focus:border-gold sm:w-auto"
|
||||
className="w-full flex-1 rounded-md border border-gold/30 bg-white/50 px-2 py-1 text-sm text-text-marble outline-none focus:border-gold sm:w-auto"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -93,10 +93,10 @@ function MemberRow({ member, isSelf }: { member: Member; isSelf: boolean }) {
|
||||
value={role}
|
||||
onChange={(event) => setRole(event.target.value as Role)}
|
||||
disabled={isSelf}
|
||||
className="rounded-md border border-navy/20 bg-white px-2 py-1 text-sm outline-none focus:border-gold disabled:opacity-50"
|
||||
className="rounded-md border border-gold/30 bg-white/50 px-2 py-1 text-sm text-text-marble outline-none focus:border-gold disabled:opacity-50"
|
||||
>
|
||||
<option value="public">public</option>
|
||||
<option value="judge">judge</option>
|
||||
<option value="public">Citoyen</option>
|
||||
<option value="judge">Archonte</option>
|
||||
</select>
|
||||
|
||||
{pseudoLocked ? (
|
||||
@@ -104,26 +104,26 @@ function MemberRow({ member, isSelf }: { member: Member; isSelf: boolean }) {
|
||||
type="button"
|
||||
onClick={handleUnlock}
|
||||
disabled={saving}
|
||||
className="whitespace-nowrap rounded-md border border-navy/20 px-2 py-1 text-xs text-navy hover:bg-navy/5 disabled:opacity-50"
|
||||
className="whitespace-nowrap rounded-md border border-gold/30 px-2 py-1 text-xs text-text-marble hover:bg-gold/10 disabled:opacity-50"
|
||||
>
|
||||
Déverrouiller le pseudo
|
||||
</button>
|
||||
) : (
|
||||
<span className="whitespace-nowrap text-xs text-ink/50">pseudo libre</span>
|
||||
<span className="whitespace-nowrap text-xs text-text-mut">pseudo libre</span>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSave}
|
||||
disabled={saving || !dirty}
|
||||
className="whitespace-nowrap rounded-md bg-navy px-3 py-1.5 text-sm font-medium text-ivory transition hover:bg-navy/90 disabled:opacity-40 sm:ml-auto"
|
||||
className="whitespace-nowrap rounded-md bg-ink-2 px-3 py-1.5 text-sm font-medium text-gold-bright transition hover:bg-ink disabled:opacity-40 sm:ml-auto"
|
||||
>
|
||||
{saving ? "…" : "Enregistrer"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{error && <p className="text-xs text-red-700">{error}</p>}
|
||||
{success && !dirty && <p className="text-xs text-green-700">OK</p>}
|
||||
{error && <p className="text-xs text-oxblood">{error}</p>}
|
||||
{success && !dirty && <p className="text-xs text-olive">OK</p>}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
@@ -136,7 +136,7 @@ export function AdminMembersTable({
|
||||
currentUserId: string;
|
||||
}) {
|
||||
if (members.length === 0) {
|
||||
return <p className="text-sm text-ink/70">Aucun membre inscrit.</p>;
|
||||
return <p className="text-sm text-marble/60">Aucun Citoyen inscrit.</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -33,7 +33,12 @@ export default async function AdminPage() {
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-3xl px-4 py-8">
|
||||
<div className="mb-6 flex flex-wrap items-center justify-between gap-3">
|
||||
<h1 className="text-2xl font-semibold text-navy">Admin</h1>
|
||||
<div>
|
||||
<h1 className="font-heading text-2xl tracking-[0.1em] text-gold-bright uppercase">
|
||||
Le Conseil des Archontes
|
||||
</h1>
|
||||
<p className="font-serif text-sm text-marble/60 italic">Administration des Citoyens</p>
|
||||
</div>
|
||||
<ResetRoundButton />
|
||||
</div>
|
||||
<AdminMembersTable members={members ?? []} currentUserId={user.id} />
|
||||
|
||||
@@ -21,7 +21,7 @@ export function ResetRoundButton() {
|
||||
type="button"
|
||||
onClick={handleClick}
|
||||
disabled={state === "loading"}
|
||||
className="rounded-md border border-navy/20 bg-white px-3 py-1.5 text-sm font-medium text-navy shadow-sm transition hover:bg-navy/5 disabled:opacity-50"
|
||||
className="marble-surface rounded-md border border-gold/40 px-3 py-1.5 text-sm font-medium text-text-marble shadow-sm transition hover:bg-gold/10 disabled:opacity-50"
|
||||
>
|
||||
{state === "loading" ? "…" : state === "done" ? "Repère mis à jour ✓" : "Nouveau round (réinitialiser le repère)"}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user