"use client"; import { useEffect, useState, useCallback } from "react"; import { GAME_META, GameId } from "@/lib/levels"; import { GAME_RULES } from "@/lib/rules"; interface Props { game: GameId; /** Force-show regardless of localStorage (e.g. when user clicks "?") */ forceShow?: boolean; onClose?: () => void; } function seenKey(game: GameId) { return `rule-seen-${game}`; } export function useRuleOverlay(game: GameId) { const [visible, setVisible] = useState(false); useEffect(() => { if (typeof window === "undefined") return; const seen = localStorage.getItem(seenKey(game)); if (!seen) setVisible(true); }, [game]); const dismiss = useCallback(() => { if (typeof window !== "undefined") { localStorage.setItem(seenKey(game), "1"); } setVisible(false); }, [game]); const open = useCallback(() => setVisible(true), []); return { visible, dismiss, open }; } export default function RuleOverlay({ game, forceShow, onClose }: Props) { const { visible, dismiss } = useRuleOverlay(game); const isOpen = forceShow || visible; const handleClose = useCallback(() => { dismiss(); onClose?.(); }, [dismiss, onClose]); // Close on Escape useEffect(() => { if (!isOpen) return; const handler = (e: KeyboardEvent) => { if (e.key === "Escape") handleClose(); }; window.addEventListener("keydown", handler); return () => window.removeEventListener("keydown", handler); }, [isOpen, handleClose]); if (!isOpen) return null; const { name, accent, symbol } = GAME_META[game]; const rules = GAME_RULES[game]; if (!rules) return null; return (
e.stopPropagation()} > {/* Header */}
{symbol}

{name}

{rules.duration}

{/* Subtitle */}

{rules.subtitle}

{/* Rules */}
{rules.howToPlay.map((rule, i) => (
{i + 1}

{rule}

))}
{/* Tip */} {rules.tip && (
💡

{rules.tip}

)} {/* CTA */}
); }