Passe Le Vol d'Icare en plein écran avec podium animé pour le top 3
Build and deploy / deploy (push) Successful in 35s
Build and deploy / deploy (push) Successful in 35s
Le classement (dont un nouveau podium top 3, réutilisant celui de L'Agora) vit maintenant dans une modale entièrement détachée de la mise en page du jeu : une mise à jour Realtime du classement pendant une partie ne peut plus redimensionner le canvas et casser la partie en cours. Le jeu occupe tout l'écran disponible (contain avec letterboxing) au lieu d'une carte fixe en haut de page. Corrige aussi le score du classement, en bleu au lieu de doré (contraste insuffisant sur fond marbre clair). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -175,10 +175,19 @@ export function IcarusGame({ onFinish }: { onFinish: (score: number) => void })
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) return;
|
||||
|
||||
// "Contain" dans le conteneur (largeur ET hauteur, contrairement à avant
|
||||
// où seule la largeur comptait) : nécessaire en plein écran, où la
|
||||
// hauteur disponible varie et n'est plus déduite de la largeur.
|
||||
function resize() {
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
const cssWidth = container!.clientWidth;
|
||||
const cssHeight = cssWidth * (VIEWPORT_HEIGHT / VIEWPORT_WIDTH);
|
||||
const availableWidth = container!.clientWidth;
|
||||
const availableHeight = container!.clientHeight;
|
||||
let cssWidth = availableWidth;
|
||||
let cssHeight = (cssWidth * VIEWPORT_HEIGHT) / VIEWPORT_WIDTH;
|
||||
if (cssHeight > availableHeight) {
|
||||
cssHeight = availableHeight;
|
||||
cssWidth = (cssHeight * VIEWPORT_WIDTH) / VIEWPORT_HEIGHT;
|
||||
}
|
||||
canvas!.width = cssWidth * dpr;
|
||||
canvas!.height = cssHeight * dpr;
|
||||
canvas!.style.width = `${cssWidth}px`;
|
||||
@@ -283,38 +292,38 @@ export function IcarusGame({ onFinish }: { onFinish: (score: number) => void })
|
||||
typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-3">
|
||||
<div
|
||||
ref={containerRef}
|
||||
onPointerDown={requestFlap}
|
||||
className="relative w-full max-w-xs touch-none select-none overflow-hidden rounded-2xl border border-gold/40 shadow-xl"
|
||||
>
|
||||
<canvas ref={canvasRef} className="block h-full w-full" />
|
||||
<div
|
||||
ref={containerRef}
|
||||
onPointerDown={requestFlap}
|
||||
className="relative flex flex-1 touch-none items-center justify-center overflow-hidden bg-ink select-none"
|
||||
>
|
||||
<canvas ref={canvasRef} className="block" />
|
||||
|
||||
{status === "dead" && !prefersReducedMotion && <Confetti />}
|
||||
|
||||
{status === "dead" && (
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-ink/50">
|
||||
<div className="marble-surface animate-reveal flex flex-col items-center gap-2 rounded-xl border border-gold/40 px-6 py-4 text-center shadow-lg">
|
||||
<p className="text-xs tracking-wide text-text-mut uppercase">Score</p>
|
||||
<p className="font-heading text-3xl text-gold-bright">{score}</p>
|
||||
<button
|
||||
type="button"
|
||||
onPointerDown={(event) => event.stopPropagation()}
|
||||
onClick={resetGame}
|
||||
className="mt-1 rounded-md bg-ink-2 px-4 py-2 font-heading text-sm tracking-wide text-gold-bright uppercase transition hover:bg-ink"
|
||||
>
|
||||
Rejouer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{status === "dead" && !prefersReducedMotion && <Confetti />}
|
||||
|
||||
{status === "idle" && (
|
||||
<p className="text-center text-sm text-marble/60">
|
||||
Touche l'écran pour battre des ailes et t'envoler entre les colonnes.
|
||||
</p>
|
||||
<div className="pointer-events-none absolute inset-x-0 bottom-10 flex justify-center px-6">
|
||||
<p className="marble-surface animate-reveal rounded-lg border border-gold/40 px-4 py-2 text-center text-sm text-text-marble shadow-lg">
|
||||
Touche l'écran pour battre des ailes et t'envoler entre les colonnes.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status === "dead" && (
|
||||
<div className="absolute inset-0 flex items-center justify-center bg-ink/50">
|
||||
<div className="marble-surface animate-reveal flex flex-col items-center gap-2 rounded-xl border border-gold/40 px-6 py-4 text-center shadow-lg">
|
||||
<p className="text-xs tracking-wide text-text-mut uppercase">Score</p>
|
||||
<p className="font-heading text-3xl text-gold-bright">{score}</p>
|
||||
<button
|
||||
type="button"
|
||||
onPointerDown={(event) => event.stopPropagation()}
|
||||
onClick={resetGame}
|
||||
className="mt-1 rounded-md bg-ink-2 px-4 py-2 font-heading text-sm tracking-wide text-gold-bright uppercase transition hover:bg-ink"
|
||||
>
|
||||
Rejouer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user