// @ts-nocheck // This file bundles all logic (Components, Services, Types) to run directly in the browser. // Explicitly access globals to ensure we use the UMD build const React = window.React; const ReactDOM = window.ReactDOM; const { useState, useEffect, useRef, useCallback } = React; // --- CONFIGURATION --- const PUZZLE_IMAGES = [ "images/puzzle1.jpg", "images/puzzle2.jpg", "images/puzzle3.jpg" ]; const BG_IMAGE = "bg.jpg"; // --- TYPES --- const ViewState = { MENU: 'MENU', GAME: 'GAME', }; // --- SERVICES --- const STORAGE_KEY = 'cubes_leaderboard'; const getScores = async () => { const stored = localStorage.getItem(STORAGE_KEY); if (!stored) return []; try { return JSON.parse(stored); } catch (e) { return []; } }; const saveScore = async (newScore) => { const currentScores = await getScores(); const updatedScores = [...currentScores, newScore]; // Sort by time (ascending) updatedScores.sort((a, b) => a.time - b.time); // Keep top 20 const top20 = updatedScores.slice(0, 20); localStorage.setItem(STORAGE_KEY, JSON.stringify(top20)); return top20; }; // --- COMPONENTS --- // 1. Leaderboard Component const Leaderboard = ({ onClose, highlightName }) => { const [scores, setScores] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { const fetchScores = async () => { const data = await getScores(); setScores(data); setLoading(false); }; fetchScores(); }, []); const formatTime = (ms) => { const seconds = Math.floor(ms / 1000); const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`; }; return (

Tabuľka výsledkov

{loading ? (
Načítavam...
) : scores.length === 0 ? (
Zatiaľ žiadne výsledky. Buď prvý!
) : ( {scores.map((score, index) => ( ))}
# Meno Čas
{index + 1}. {score.name} {index === 0 && 👑} {formatTime(score.time)}
)}
); }; // 2. Main Menu Component const MainMenu = ({ onNavigate }) => { return (
{/* Background Image Layer */}
e.target.style.display = 'none'} alt="Background" className="w-full h-full object-cover opacity-20" />
{/* Content Layer */}
{/* Header Area */}

CAPOLI FUN

Herná zóna

{/* 6-Grid Layout for Games */}
{/* Game 1: CUBES (Active) */} {/* Game 2: PONG (PRIPRAVUJEME 2) - Opravený ODKAZ na https://capoli.net/fun/pong/index.html */} {/* Corner accent (šedý) */}

PONG

PONG

Classic arcade

{/* Placeholder Slots 3-6 (pre ostávajúce 4 voľné sloty) */} {Array.from({ length: 4 }).map((_, index) => (
{index + 3}
Pripravujeme
))}
© 2024 Capoli.net
); }; // 3. Game Component const CubesGame = ({ onBack }) => { const GRID_SIZE = 5; const TILE_COUNT = GRID_SIZE * GRID_SIZE; const EMPTY_INDEX = TILE_COUNT - 1; // Game State const [grid, setGrid] = useState([]); const [isGameActive, setIsGameActive] = useState(false); const [isSolved, setIsSolved] = useState(false); const [moveCount, setMoveCount] = useState(0); // Timer State const [startTime, setStartTime] = useState(null); const [elapsedTime, setElapsedTime] = useState(0); // Settings const [currentImageIndex, setCurrentImageIndex] = useState(0); const [playerName, setPlayerName] = useState(''); const [showLeaderboard, setShowLeaderboard] = useState(false); const timerRef = useRef(null); // Initialize ordered grid const getSolvedGrid = () => Array.from({ length: TILE_COUNT }, (_, i) => i); // Start/Reset Game const initGame = useCallback(() => { const solved = getSolvedGrid(); // Shuffle logic let tempGrid = [...solved]; let emptyPos = EMPTY_INDEX; let previousPos = -1; // Perform 200 random moves for (let i = 0; i < 200; i++) { const neighbors = []; const row = Math.floor(emptyPos / GRID_SIZE); const col = emptyPos % GRID_SIZE; if (row > 0) neighbors.push(emptyPos - GRID_SIZE); // Up if (row < GRID_SIZE - 1) neighbors.push(emptyPos + GRID_SIZE); // Down if (col > 0) neighbors.push(emptyPos - 1); // Left if (col < GRID_SIZE - 1) neighbors.push(emptyPos + 1); // Right const validNeighbors = neighbors.filter(n => n !== previousPos); if (validNeighbors.length > 0) { const randomNeighbor = validNeighbors[Math.floor(Math.random() * validNeighbors.length)]; // Swap tempGrid[emptyPos] = tempGrid[randomNeighbor]; tempGrid[randomNeighbor] = EMPTY_INDEX; previousPos = emptyPos; emptyPos = randomNeighbor; } } setGrid(tempGrid); setIsGameActive(false); setIsSolved(false); setMoveCount(0); setStartTime(null); setElapsedTime(0); if (timerRef.current) clearInterval(timerRef.current); }, []); useEffect(() => { initGame(); return () => { if (timerRef.current) clearInterval(timerRef.current); }; }, [initGame, currentImageIndex]); // Timer Effect useEffect(() => { if (isGameActive && !isSolved) { timerRef.current = window.setInterval(() => { setElapsedTime(Date.now() - (startTime || Date.now())); }, 100); } else { if (timerRef.current) clearInterval(timerRef.current); } return () => { if (timerRef.current) clearInterval(timerRef.current); }; }, [isGameActive, isSolved, startTime]); const handleTileClick = (index) => { if (isSolved) return; if (!isGameActive) { setIsGameActive(true); setStartTime(Date.now()); } const emptyPos = grid.indexOf(EMPTY_INDEX); const row = Math.floor(index / GRID_SIZE); const col = index % GRID_SIZE; const emptyRow = Math.floor(emptyPos / GRID_SIZE); const emptyCol = emptyPos % GRID_SIZE; const isAdjacent = (Math.abs(row - emptyRow) === 1 && col === emptyCol) || (Math.abs(col - emptyCol) === 1 && row === emptyRow); if (isAdjacent) { const newGrid = [...grid]; newGrid[emptyPos] = newGrid[index]; newGrid[index] = EMPTY_INDEX; setGrid(newGrid); setMoveCount(prev => prev + 1); // Check win const isWin = newGrid.every((val, idx) => val === idx); if (isWin) { setIsSolved(true); setIsGameActive(false); } } }; const handleSaveScore = async () => { if (!playerName.trim()) { alert("Prosím zadaj meno (max 8 znakov)"); return; } await saveScore({ name: playerName.trim().substring(0, 8), time: elapsedTime, date: new Date().toISOString() }); setShowLeaderboard(true); }; const formatTime = (ms) => { const seconds = Math.floor(ms / 1000); const minutes = Math.floor(seconds / 60); return `${minutes.toString().padStart(2, '0')}:${(seconds % 60).toString().padStart(2, '0')}`; }; return (
{/* Top Bar */}

CUBES

Ťahy: {moveCount}
{formatTime(elapsedTime)}
{/* Main Game Area */}
{/* The Grid */}
{/* Success Overlay */} {isSolved && (

HOTOVO!

{formatTime(elapsedTime)}

setPlayerName(e.target.value)} className="p-3 rounded text-capoliBlue text-center font-bold text-xl uppercase outline-none border-4 border-transparent focus:border-capoliYellow transition-colors" placeholder="TVOJE MENO" />
)}
{grid.map((tileNumber, index) => { const originalRow = Math.floor(tileNumber / GRID_SIZE); const originalCol = tileNumber % GRID_SIZE; const isBlank = tileNumber === EMPTY_INDEX; return (
handleTileClick(index)} className={` relative w-full h-full overflow-hidden transition-all duration-100 rounded-sm ${isBlank ? 'opacity-0 cursor-default' : 'cursor-pointer hover:brightness-110 shadow-inner'} `} style={{ backgroundColor: '#e5e7eb' }} > {!isBlank && (
)}
); })}
{/* Controls & Mini View */}
{/* Preview */}
Predloha
{ // Fallback if image not found e.target.style.display='none'; e.target.parentElement.innerHTML += '
Obrázok nenájdený.
Nahrajte puzzle1.jpg
'; }} alt="Target" className="w-full h-full object-cover" />
{/* Controls */}
{PUZZLE_IMAGES.map((img, idx) => ( ))}
{showLeaderboard && ( setShowLeaderboard(false)} highlightName={playerName} /> )}
); }; // --- APP ROOT --- const App = () => { const [currentView, setCurrentView] = useState(ViewState.MENU); return ( // Global Framing (The "Capoli" Frame)
{/* Inner Gold Border */}
{/* Main Content Area */}
{currentView === ViewState.MENU && ( )} {currentView === ViewState.GAME && ( setCurrentView(ViewState.MENU)} /> )}
); }; // Mount the App const rootElement = document.getElementById('root'); if (rootElement) { const root = ReactDOM.createRoot(rootElement); root.render(); }