puzzle-trainer/app/levels/page.tsx
2026-05-23 01:05:21 +00:00

81 lines
2.6 KiB
TypeScript

"use client";
import Link from "next/link";
import { useEffect, useState } from "react";
import { GAME_META, GAMES, GameId, TOTAL_LEVELS } from "@/lib/levels";
function getLevelProgress(game: GameId): number {
if (typeof window === "undefined") return 0;
try {
const raw = localStorage.getItem(`levels-${game}`);
if (!raw) return 0;
const data = JSON.parse(raw);
return data.maxUnlocked ?? 0;
} catch { return 0; }
}
function GameCard({ game }: { game: GameId }) {
const meta = GAME_META[game];
const [progress, setProgress] = useState(0);
useEffect(() => {
setProgress(getLevelProgress(game));
}, [game]);
const pct = Math.round((progress / TOTAL_LEVELS) * 100);
return (
<Link
href={`/${game}/levels`}
className="block bg-white rounded-2xl p-4 shadow-sm border border-gray-100 active:scale-[0.98] transition-transform"
>
<div className="flex items-center gap-3 mb-3">
<span className="text-2xl" style={{ fontFamily: "monospace" }}>{meta.symbol}</span>
<div className="flex-1 min-w-0">
<p className="font-bold text-gray-900 text-base leading-tight">{meta.name}</p>
<p className="text-xs text-gray-400 truncate">{meta.subtitle}</p>
</div>
<div className="text-right">
<p className="text-sm font-bold" style={{ color: meta.accent }}>{progress}</p>
<p className="text-[10px] text-gray-400">/ {TOTAL_LEVELS}</p>
</div>
</div>
{/* Progress bar */}
<div className="h-1.5 bg-gray-100 rounded-full overflow-hidden">
<div
className="h-full rounded-full transition-all duration-500"
style={{ width: `${pct}%`, backgroundColor: meta.accent }}
/>
</div>
<div className="flex justify-between mt-1">
<p className="text-[10px] text-gray-400">{meta.duration}</p>
<p className="text-[10px] text-gray-400">{pct}% complété</p>
</div>
</Link>
);
}
export default function LevelsHubPage() {
return (
<div className="px-4 pb-6">
{/* Header */}
<div className="pt-4 pb-5">
<h1 className="text-2xl font-bold text-gray-900">Entraînement</h1>
<p className="text-sm text-gray-500 mt-0.5">100 niveaux par jeu, du facile à l'expert</p>
</div>
{/* Game cards */}
<div className="flex flex-col gap-3">
{GAMES.map(game => (
<GameCard key={game} game={game} />
))}
</div>
{/* Footer hint */}
<p className="text-center text-xs text-gray-400 mt-6">
Résous les niveaux du quotidien pour débloquer les suivants
</p>
</div>
);
}