Passe de polish visuel sur tout le site
Corrige deux incohérences trouvées en chemin : le compteur de passages dans le char en gold-bright sur marbre (même défaut de contraste déjà vu ailleurs), et le point du Crieur toujours rouge même pour un honneur positif. Réutilise les ornements existants mais jamais appelés (meander-divider entre le podium et le classement, DiamondDivider sur /profile avec une nouvelle convention de carte secondaire). Ajoute une ambiance discrète (fond qui respire très lentement, halo doré sur les cartes marbre, désactivés sous prefers-reduced-motion), étend les confettis et un nouveau son à Icare pour la parité avec la Corne d'Abondance, des loading.tsx sur les pages les plus consultées, et un petit ornement sur les états vides plutôt qu'un texte brut. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
"use client";
|
||||
|
||||
import { useState, type CSSProperties } from "react";
|
||||
|
||||
const CONFETTI_COLORS = ["#E7C560", "#C9A227", "#F4ECD8", "#A5342A", "#5E6B3B", "#2E6E7E", "#B08D57"];
|
||||
|
||||
type ConfettiPiece = {
|
||||
id: number;
|
||||
left: number;
|
||||
color: string;
|
||||
delay: number;
|
||||
duration: number;
|
||||
spin: number;
|
||||
drift: number;
|
||||
};
|
||||
|
||||
function generateConfettiPieces(): ConfettiPiece[] {
|
||||
return Array.from({ length: 26 }, (_, index) => ({
|
||||
id: index,
|
||||
left: Math.random() * 100,
|
||||
color: CONFETTI_COLORS[index % CONFETTI_COLORS.length],
|
||||
delay: Math.random() * 250,
|
||||
duration: 900 + Math.random() * 700,
|
||||
spin: (Math.random() > 0.5 ? 1 : -1) * (360 + Math.random() * 360),
|
||||
drift: (Math.random() - 0.5) * 70,
|
||||
}));
|
||||
}
|
||||
|
||||
// Partagé entre Le Vol d'Icare et La Corne d'Abondance (fin de partie) —
|
||||
// à l'appelant de ne le monter que si prefers-reduced-motion ne le
|
||||
// désactive pas, comme déjà fait sur les deux jeux.
|
||||
export function Confetti() {
|
||||
// Initialiseur paresseux de useState (n'exécute Math.random() qu'une
|
||||
// seule fois, au montage — Confetti est remonté à chaque nouvelle partie
|
||||
// terminée) plutôt qu'un appel impur dans le corps du composant.
|
||||
const [pieces] = useState(generateConfettiPieces);
|
||||
|
||||
return (
|
||||
<div className="pointer-events-none absolute inset-0 overflow-hidden">
|
||||
{pieces.map((piece) => (
|
||||
<span
|
||||
key={piece.id}
|
||||
className="animate-confetti-fall absolute top-0 h-2.5 w-1.5 rounded-[1px]"
|
||||
style={
|
||||
{
|
||||
left: `${piece.left}%`,
|
||||
backgroundColor: piece.color,
|
||||
animationDelay: `${piece.delay}ms`,
|
||||
animationDuration: `${piece.duration}ms`,
|
||||
"--confetti-spin": `${piece.spin}deg`,
|
||||
"--confetti-drift": `${piece.drift}px`,
|
||||
} as CSSProperties
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user