Initial commit
This commit is contained in:
commit
c87ebf0a74
22 changed files with 4973 additions and 0 deletions
147
App.tsx
Normal file
147
App.tsx
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
import React from 'react';
|
||||
import { useGame } from './hooks/useGame';
|
||||
import { Landing } from './components/Landing';
|
||||
import { Lobby } from './components/Lobby';
|
||||
import { GameScreen } from './components/GameScreen';
|
||||
import { Scoreboard } from './components/Scoreboard';
|
||||
import { Podium } from './components/Podium';
|
||||
import { QuizCreator } from './components/QuizCreator';
|
||||
import { RevealScreen } from './components/RevealScreen';
|
||||
|
||||
const FloatingShapes = () => {
|
||||
// Deterministic "random" for SSR safety if needed, but client-side is fine here
|
||||
const shapes = [...Array(15)].map((_, i) => ({
|
||||
left: `${Math.random() * 100}%`,
|
||||
width: `${Math.random() * 100 + 40}px`,
|
||||
height: `${Math.random() * 100 + 40}px`,
|
||||
animationDuration: `${Math.random() * 20 + 15}s`,
|
||||
animationDelay: `-${Math.random() * 20}s`,
|
||||
borderRadius: Math.random() > 0.5 ? '50%' : '20%', // Mix of circles and rounded squares
|
||||
background: 'rgba(255, 255, 255, 0.05)',
|
||||
}));
|
||||
|
||||
return (
|
||||
<>
|
||||
{shapes.map((style, i) => (
|
||||
<div key={i} className="floating-shape" style={style} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
function App() {
|
||||
const {
|
||||
role,
|
||||
gameState,
|
||||
quiz,
|
||||
players,
|
||||
currentQuestionIndex,
|
||||
timeLeft,
|
||||
error,
|
||||
gamePin,
|
||||
startQuizGen,
|
||||
startManualCreation,
|
||||
finalizeManualQuiz,
|
||||
joinGame,
|
||||
startGame,
|
||||
handleAnswer,
|
||||
hasAnswered,
|
||||
lastPointsEarned,
|
||||
nextQuestion,
|
||||
currentCorrectShape
|
||||
} = useGame();
|
||||
|
||||
const currentQ = quiz?.questions[currentQuestionIndex];
|
||||
|
||||
// Logic to find correct option, handling both Host (has isCorrect flag) and Client (masked, needs shape)
|
||||
const correctOpt = currentQ?.options.find(o => {
|
||||
if (role === 'HOST') return o.isCorrect;
|
||||
return o.shape === currentCorrectShape;
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="min-h-screen text-white relative">
|
||||
<FloatingShapes />
|
||||
|
||||
<div className="relative z-10">
|
||||
{gameState === 'LANDING' || gameState === 'GENERATING' ? (
|
||||
<Landing
|
||||
onGenerate={startQuizGen}
|
||||
onCreateManual={startManualCreation}
|
||||
onJoin={joinGame}
|
||||
isLoading={gameState === 'GENERATING'}
|
||||
error={error}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{gameState === 'CREATING' ? (
|
||||
<QuizCreator
|
||||
onFinalize={finalizeManualQuiz}
|
||||
onCancel={() => window.location.reload()}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{gameState === 'LOBBY' ? (
|
||||
<Lobby
|
||||
quizTitle={quiz?.title || 'OpenHoot'}
|
||||
players={players}
|
||||
gamePin={gamePin}
|
||||
role={role}
|
||||
onStart={startGame}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{(gameState === 'COUNTDOWN' || gameState === 'QUESTION') && quiz ? (
|
||||
gameState === 'COUNTDOWN' ? (
|
||||
<div className="flex flex-col items-center justify-center h-screen animate-bounce">
|
||||
<div className="text-4xl font-display font-bold mb-4">Get Ready!</div>
|
||||
<div className="text-[12rem] font-black leading-none drop-shadow-[0_10px_0_rgba(0,0,0,0.3)]">
|
||||
{timeLeft}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<GameScreen
|
||||
question={quiz.questions[currentQuestionIndex]}
|
||||
timeLeft={timeLeft}
|
||||
totalQuestions={quiz.questions.length}
|
||||
currentQuestionIndex={currentQuestionIndex}
|
||||
gameState={gameState}
|
||||
role={role}
|
||||
onAnswer={handleAnswer}
|
||||
hasAnswered={hasAnswered}
|
||||
lastPointsEarned={lastPointsEarned}
|
||||
/>
|
||||
)
|
||||
) : null}
|
||||
|
||||
{gameState === 'REVEAL' && correctOpt ? (
|
||||
<RevealScreen
|
||||
isCorrect={lastPointsEarned !== null && lastPointsEarned > 0}
|
||||
pointsEarned={lastPointsEarned || 0}
|
||||
newScore={0}
|
||||
streak={0}
|
||||
correctOption={correctOpt}
|
||||
role={role}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{gameState === 'SCOREBOARD' ? (
|
||||
<Scoreboard
|
||||
players={players}
|
||||
onNext={nextQuestion}
|
||||
isHost={role === 'HOST'}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{gameState === 'PODIUM' ? (
|
||||
<Podium
|
||||
players={players}
|
||||
onRestart={() => window.location.reload()}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
Loading…
Add table
Add a link
Reference in a new issue