feat: add about page, global stats counter, and blitz screen updates
- Create about page with game modes, technologies, and paliers - Add stats API endpoint for global game counter - Update home screen with emoji-based tier system (🌱-🚀) - Rewrite BlitzScreen to match new puzzle-based win/lose phases - Add simple-icons package for tech stack icons - Update metadata with wikirush.xyz domain - Fix em dashes to hyphens throughout codebase - Update footer with privacy and about links
This commit is contained in:
@@ -25,7 +25,7 @@ export function BlitzScreen({ onBack }: { onBack: () => void }) {
|
||||
<div className="text-5xl">⚡</div>
|
||||
<h2 className="text-2xl sm:text-3xl font-black">Mode Blitz</h2>
|
||||
<p className="text-[#888] text-sm sm:text-base leading-relaxed">
|
||||
Tu as <span className="text-[#f0f0f0] font-bold">2 minutes</span> pour visiter un maximum d'articles Wikipedia différents en cliquant sur les liens. Ton score = nombre d'articles uniques visités.
|
||||
Tu as <span className="text-[#f0f0f0] font-bold">2 minutes</span>{" "}pour naviguer de l'article de départ jusqu'à l'article cible en cliquant sur les liens Wikipedia. Plus tu es rapide, mieux c'est !
|
||||
</p>
|
||||
<button className={btnPrimary} onClick={game.start} disabled={game.loading}>
|
||||
{game.loading ? "Préparation..." : "Lancer le chrono !"}
|
||||
@@ -33,26 +33,37 @@ export function BlitzScreen({ onBack }: { onBack: () => void }) {
|
||||
</div>
|
||||
);
|
||||
|
||||
if (game.phase === "ended") return (
|
||||
if (game.phase === "won") return (
|
||||
<div className="min-h-dvh bg-[#0f0f0f] text-[#f0f0f0] animate-fade-in flex items-center justify-center px-4 py-8">
|
||||
<div className="w-full max-w-sm sm:max-w-md text-center flex flex-col gap-5">
|
||||
<div className="text-5xl sm:text-6xl leading-none">⚡</div>
|
||||
<h2 className="text-2xl sm:text-3xl font-black">Temps écoulé !</h2>
|
||||
<div className="text-5xl sm:text-6xl leading-none">🎉</div>
|
||||
<h2 className="text-2xl sm:text-3xl font-black">Article trouvé !</h2>
|
||||
{game.puzzle && (
|
||||
<p className="text-[#888] text-sm">
|
||||
<span className="text-[#f0f0f0] font-semibold">{game.puzzle.start}</span>
|
||||
{" → "}
|
||||
<span className="text-[#7c3aed] font-semibold">{game.puzzle.target}</span>
|
||||
</p>
|
||||
)}
|
||||
<div className="flex gap-8 justify-center">
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-4xl font-black text-[#7c3aed]">{game.visited.length}</span>
|
||||
<span className="text-xs text-[#888]">articles visités</span>
|
||||
<span className="text-4xl font-black text-[#7c3aed]">{fmtLeft(game.timeLeft)}</span>
|
||||
<span className="text-xs text-[#888]">temps restant</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-4xl font-black text-[#7c3aed]">{game.clicks}</span>
|
||||
<span className="text-xs text-[#888]">clics</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-4xl font-black text-[#7c3aed]">{game.history.length}</span>
|
||||
<span className="text-xs text-[#888]">articles</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-[#1a1a1a] rounded-xl px-4 py-3 flex flex-wrap gap-1 text-xs text-[#888] text-left max-h-48 overflow-y-auto">
|
||||
{game.visited.map((t, i) => (
|
||||
{game.history.map((t, i) => (
|
||||
<span key={i} className="flex items-center gap-1">
|
||||
{i > 0 && <span className="text-[#555]">›</span>}
|
||||
<span>{t}</span>
|
||||
<span className={t === game.puzzle?.target ? "text-[#7c3aed] font-bold" : ""}>{t}</span>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
@@ -60,7 +71,48 @@ export function BlitzScreen({ onBack }: { onBack: () => void }) {
|
||||
<button className={btnPrimary} onClick={game.start} disabled={game.loading}>
|
||||
Rejouer
|
||||
</button>
|
||||
<button className={btnGhost} onClick={onBack}>Accueil</button>
|
||||
<button className={btnGhost} onClick={() => { game.reset(); onBack(); }}>Accueil</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (game.phase === "lost") return (
|
||||
<div className="min-h-dvh bg-[#0f0f0f] text-[#f0f0f0] animate-fade-in flex items-center justify-center px-4 py-8">
|
||||
<div className="w-full max-w-sm sm:max-w-md text-center flex flex-col gap-5">
|
||||
<div className="text-5xl sm:text-6xl leading-none">⏱️</div>
|
||||
<h2 className="text-2xl sm:text-3xl font-black">Temps écoulé !</h2>
|
||||
{game.puzzle && (
|
||||
<p className="text-[#888] text-sm">
|
||||
L'objectif était d'atteindre{" "}
|
||||
<span className="text-[#7c3aed] font-semibold">{game.puzzle.target}</span>
|
||||
</p>
|
||||
)}
|
||||
<div className="flex gap-8 justify-center">
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-4xl font-black text-red-400">{game.clicks}</span>
|
||||
<span className="text-xs text-[#888]">clics</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-4xl font-black text-red-400">{game.history.length}</span>
|
||||
<span className="text-xs text-[#888]">articles visités</span>
|
||||
</div>
|
||||
</div>
|
||||
{game.history.length > 0 && (
|
||||
<div className="bg-[#1a1a1a] rounded-xl px-4 py-3 flex flex-wrap gap-1 text-xs text-[#888] text-left max-h-48 overflow-y-auto">
|
||||
{game.history.map((t, i) => (
|
||||
<span key={i} className="flex items-center gap-1">
|
||||
{i > 0 && <span className="text-[#555]">›</span>}
|
||||
<span>{t}</span>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col gap-2.5">
|
||||
<button className={btnPrimary} onClick={game.start} disabled={game.loading}>
|
||||
Réessayer
|
||||
</button>
|
||||
<button className={btnGhost} onClick={() => { game.reset(); onBack(); }}>Accueil</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -90,26 +142,32 @@ export function BlitzScreen({ onBack }: { onBack: () => void }) {
|
||||
</div>
|
||||
|
||||
{/* Bottom bar */}
|
||||
<div className="fixed bottom-0 left-0 right-0 z-50 bg-[#0f0f0f]/97 backdrop-blur-sm border-t border-[#2e2e2e] flex items-center justify-between px-3 sm:px-4 py-2 gap-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex flex-col items-center gap-0.5">
|
||||
<span className="text-[8px] font-bold uppercase tracking-wider text-[#888]">⚡ Articles</span>
|
||||
<span className="text-sm font-black text-[#7c3aed] tabular-nums">{game.visited.length}</span>
|
||||
<div className="fixed bottom-0 left-0 right-0 z-50 bg-[#0f0f0f]/97 backdrop-blur-sm border-t border-[#2e2e2e] px-3 sm:px-4 py-2 flex flex-col gap-1">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex flex-col items-center gap-0.5">
|
||||
<span className="text-[8px] font-bold uppercase tracking-wider text-[#888]">Clics</span>
|
||||
<span className="text-sm font-black tabular-nums">{game.clicks}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-0.5">
|
||||
<span className="text-[8px] font-bold uppercase tracking-wider text-[#888]">Clics</span>
|
||||
<span className="text-sm font-black tabular-nums">{game.clicks}</span>
|
||||
|
||||
{/* Timer */}
|
||||
<div className={`text-2xl sm:text-3xl font-black tabular-nums transition-colors ${danger ? "text-red-400 animate-pulse" : "text-[#f0f0f0]"}`}>
|
||||
{fmtLeft(game.timeLeft)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Timer */}
|
||||
<div className={`text-2xl sm:text-3xl font-black tabular-nums transition-colors ${danger ? "text-red-400" : "text-[#f0f0f0]"}`}>
|
||||
{fmtLeft(game.timeLeft)}
|
||||
</div>
|
||||
|
||||
<div className="text-xs text-[#888] text-right max-w-28 truncate">
|
||||
{game.visited.length > 0 ? game.visited[game.visited.length - 1] : ""}
|
||||
{game.puzzle && (
|
||||
<div className="text-right">
|
||||
<div className="text-[8px] font-bold uppercase tracking-wider text-[#888]">Cible</div>
|
||||
<div className="text-xs font-bold text-[#7c3aed] max-w-28 truncate">{game.puzzle.target}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{game.history.length > 0 && (
|
||||
<div className="text-[10px] text-[#555] truncate">
|
||||
{game.history.join(" › ")}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user