puzzle-trainer/DailyPageShell.tsx
2026-05-23 01:05:21 +00:00

91 lines
3 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import Link from "next/link";
import { loadStats } from "@/lib/stats";
import { GameId, GAME_META } from "@/lib/levels";
interface Props {
game: GameId;
date: string;
dateLabel: string;
children: React.ReactNode;
}
function fmt(s: number) {
return `${String(Math.floor(s / 60)).padStart(2, "0")}:${String(s % 60).padStart(2, "0")}`;
}
/**
* Wraps a daily puzzle page with:
* - Already-solved banner (if player already solved today)
* - Live date header
* - "Entraîne-toi" link to /game/levels
*/
export default function DailyPageShell({ game, date, dateLabel, children }: Props) {
const [solvedToday, setSolvedToday] = useState(false);
const [stats, setStats] = useState<ReturnType<typeof loadStats> | null>(null);
const { accent } = GAME_META[game];
useEffect(() => {
const s = loadStats(game);
setStats(s);
if (s.lastDate === date) {
setSolvedToday(true);
}
}, [game, date]);
return (
<div className="flex flex-col items-center gap-6">
{/* Header */}
<div className="text-center">
<h1 className="text-2xl font-bold text-gray-900 tracking-tight">{GAME_META[game].name}</h1>
<p className="text-sm text-gray-400 mt-1 capitalize">{dateLabel}</p>
</div>
{/* Already-solved banner */}
{solvedToday && stats && (
<div
className="w-full max-w-sm flex items-center gap-3 px-4 py-3 rounded-xl border"
style={{ background: `${accent}10`, borderColor: `${accent}30` }}
>
<div
className="w-8 h-8 rounded-full flex items-center justify-center shrink-0"
style={{ background: `${accent}20` }}
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={accent} strokeWidth={2.5} strokeLinecap="round" strokeLinejoin="round">
<polyline points="20 6 9 17 4 12"/>
</svg>
</div>
<div className="flex-1 min-w-0">
<p className="text-sm font-semibold text-gray-800">Déjà résolu aujourd&apos;hui</p>
{stats.bestTime > 0 && (
<p className="text-xs text-gray-500 timer-mono">Meilleur temps : {fmt(stats.bestTime)}</p>
)}
</div>
<Link
href={`/${game}/levels`}
className="shrink-0 text-xs font-semibold px-3 py-1.5 rounded-full transition-colors"
style={{ background: `${accent}18`, color: accent }}
>
Niveaux
</Link>
</div>
)}
{/* Board */}
{children}
{/* Footer links */}
<div className="flex items-center gap-4 text-sm text-gray-400">
<Link href={`/archive?game=${game}`} className="hover:text-gray-700 transition-colors">
Archives
</Link>
<span className="text-gray-200">·</span>
<Link href={`/${game}/levels`} className="hover:text-gray-700 transition-colors">
Entraînement
</Link>
</div>
</div>
);
}