358bed0c2e
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>
59 lines
1.8 KiB
TypeScript
59 lines
1.8 KiB
TypeScript
"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>
|
|
);
|
|
}
|