Initial commit

This commit is contained in:
2026-04-25 12:37:38 +03:00
committed by GitHub
commit df7302b8b0
85 changed files with 10204 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
import type { BingoSquareData } from '../types';
import { BingoSquare } from './BingoSquare';
interface BingoBoardProps {
board: BingoSquareData[];
winningSquareIds: Set<number>;
onSquareClick: (squareId: number) => void;
}
export function BingoBoard({ board, winningSquareIds, onSquareClick }: BingoBoardProps) {
return (
<div className="grid grid-cols-5 gap-1 w-full max-w-md mx-auto aspect-square">
{board.map((square) => (
<BingoSquare
key={square.id}
square={square}
isWinning={winningSquareIds.has(square.id)}
onClick={() => onSquareClick(square.id)}
/>
))}
</div>
);
}
+22
View File
@@ -0,0 +1,22 @@
interface BingoModalProps {
onDismiss: () => void;
}
export function BingoModal({ onDismiss }: BingoModalProps) {
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50">
<div className="bg-white rounded-xl p-6 max-w-xs w-full text-center shadow-xl animate-[bounce_0.5s_ease-out]">
<div className="text-5xl mb-4">🎉</div>
<h2 className="text-3xl font-bold text-amber-500 mb-2">BINGO!</h2>
<p className="text-gray-600 mb-6">You completed a line!</p>
<button
onClick={onDismiss}
className="w-full bg-accent text-white font-semibold py-3 px-6 rounded-lg active:bg-accent-light transition-colors"
>
Keep Playing
</button>
</div>
</div>
);
}
+35
View File
@@ -0,0 +1,35 @@
import type { BingoSquareData } from '../types';
interface BingoSquareProps {
square: BingoSquareData;
isWinning: boolean;
onClick: () => void;
}
export function BingoSquare({ square, isWinning, onClick }: BingoSquareProps) {
const baseClasses =
'relative flex items-center justify-center p-1 text-center border border-gray-300 rounded transition-all duration-150 select-none min-h-[60px] text-xs leading-tight';
const stateClasses = square.isMarked
? isWinning
? 'bg-amber-200 border-amber-400 text-amber-900'
: 'bg-marked border-marked-border text-green-800'
: 'bg-white text-gray-700 active:bg-gray-100';
const freeSpaceClasses = square.isFreeSpace ? 'font-bold text-sm' : '';
return (
<button
onClick={onClick}
disabled={square.isFreeSpace}
className={`${baseClasses} ${stateClasses} ${freeSpaceClasses}`}
aria-pressed={square.isMarked}
aria-label={square.isFreeSpace ? 'Free space' : square.text}
>
<span className="wrap-break-word hyphens-auto">{square.text}</span>
{square.isMarked && !square.isFreeSpace && (
<span className="absolute top-0.5 right-0.5 text-green-600 text-xs">✓</span>
)}
</button>
);
}
+55
View File
@@ -0,0 +1,55 @@
import type { BingoSquareData } from '../types';
import { BingoBoard } from './BingoBoard';
interface GameScreenProps {
board: BingoSquareData[];
winningSquareIds: Set<number>;
hasBingo: boolean;
onSquareClick: (squareId: number) => void;
onReset: () => void;
}
export function GameScreen({
board,
winningSquareIds,
hasBingo,
onSquareClick,
onReset,
}: GameScreenProps) {
return (
<div className="flex flex-col min-h-full bg-gray-50">
{/* Header */}
<header className="flex items-center justify-between p-3 bg-white border-b border-gray-200">
<button
onClick={onReset}
className="text-gray-500 text-sm px-3 py-1.5 rounded active:bg-gray-100"
>
← Back
</button>
<h1 className="font-bold text-gray-900">Bingo Mixer</h1>
<div className="w-16"></div>
</header>
{/* Instructions */}
<p className="text-center text-gray-500 text-sm py-2 px-4">
Tap a square when you find someone who matches it.
</p>
{/* Bingo indicator */}
{hasBingo && (
<div className="bg-amber-100 text-amber-800 text-center py-2 font-semibold text-sm">
🎉 BINGO! You got a line!
</div>
)}
{/* Board */}
<div className="flex-1 flex items-center justify-center p-3">
<BingoBoard
board={board}
winningSquareIds={winningSquareIds}
onSquareClick={onSquareClick}
/>
</div>
</div>
);
}
+30
View File
@@ -0,0 +1,30 @@
interface StartScreenProps {
onStart: () => void;
}
export function StartScreen({ onStart }: StartScreenProps) {
return (
<div className="flex flex-col items-center justify-center min-h-full p-6 bg-gray-50">
<div className="text-center max-w-sm">
<h1 className="text-4xl font-bold text-gray-900 mb-2">Bingo Mixer</h1>
<p className="text-lg text-gray-600 mb-8">Find your people!</p>
<div className="bg-white rounded-lg p-6 shadow-sm border border-gray-200 mb-8">
<h2 className="font-semibold text-gray-800 mb-3">How to play</h2>
<ul className="text-left text-gray-600 text-sm space-y-2">
<li>• Find people who match the questions</li>
<li>• Tap a square when you find a match</li>
<li>• Get 5 in a row to win!</li>
</ul>
</div>
<button
onClick={onStart}
className="w-full bg-accent text-white font-semibold py-4 px-8 rounded-lg text-lg active:bg-accent-light transition-colors"
>
Start Game
</button>
</div>
</div>
);
}