Rebrand to kaboot
This commit is contained in:
parent
156c210dea
commit
8a8ec9bc0e
8 changed files with 59 additions and 27 deletions
6
App.tsx
6
App.tsx
|
|
@ -55,7 +55,8 @@ function App() {
|
|||
currentCorrectShape,
|
||||
selectedOption,
|
||||
currentPlayerScore,
|
||||
currentStreak
|
||||
currentStreak,
|
||||
currentPlayerId
|
||||
} = useGame();
|
||||
|
||||
const currentQ = quiz?.questions[currentQuestionIndex];
|
||||
|
|
@ -90,7 +91,7 @@ function App() {
|
|||
|
||||
{gameState === 'LOBBY' ? (
|
||||
<Lobby
|
||||
quizTitle={quiz?.title || 'OpenHoot'}
|
||||
quizTitle={quiz?.title || 'Kaboot'}
|
||||
players={players}
|
||||
gamePin={gamePin}
|
||||
role={role}
|
||||
|
|
@ -138,6 +139,7 @@ function App() {
|
|||
players={players}
|
||||
onNext={nextQuestion}
|
||||
isHost={role === 'HOST'}
|
||||
currentPlayerId={currentPlayerId}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export const Landing: React.FC<LandingProps> = ({ onGenerate, onCreateManual, on
|
|||
<BrainCircuit size={48} className="text-white" />
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="text-5xl font-black mb-2 text-[#46178f] tracking-tight">OpenHoot</h1>
|
||||
<h1 className="text-5xl font-black mb-2 text-[#46178f] tracking-tight">Kaboot</h1>
|
||||
<p className="text-gray-500 font-bold mb-6">The AI Quiz Party</p>
|
||||
|
||||
<div className="flex bg-gray-100 p-2 rounded-2xl mb-8">
|
||||
|
|
|
|||
|
|
@ -8,10 +8,15 @@ interface ScoreboardProps {
|
|||
players: Player[];
|
||||
onNext: () => void;
|
||||
isHost: boolean;
|
||||
currentPlayerId: string | null;
|
||||
}
|
||||
|
||||
export const Scoreboard: React.FC<ScoreboardProps> = ({ players, onNext, isHost }) => {
|
||||
const sortedPlayers = [...players].sort((a, b) => b.score - a.score).slice(0, 5);
|
||||
export const Scoreboard: React.FC<ScoreboardProps> = ({ players, onNext, isHost, currentPlayerId }) => {
|
||||
const playersWithDisplayName = players.map(p => ({
|
||||
...p,
|
||||
displayName: p.id === currentPlayerId ? `${p.name} (You)` : p.name
|
||||
}));
|
||||
const sortedPlayers = [...playersWithDisplayName].sort((a, b) => b.score - a.score).slice(0, 5);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-screen p-8">
|
||||
|
|
@ -29,7 +34,7 @@ export const Scoreboard: React.FC<ScoreboardProps> = ({ players, onNext, isHost
|
|||
<XAxis type="number" hide />
|
||||
<YAxis
|
||||
type="category"
|
||||
dataKey="name"
|
||||
dataKey="displayName"
|
||||
tick={{ fontSize: 24, fontWeight: 800, fill: '#333', fontFamily: 'Fredoka' }}
|
||||
width={200}
|
||||
tickLine={false}
|
||||
|
|
@ -39,7 +44,7 @@ export const Scoreboard: React.FC<ScoreboardProps> = ({ players, onNext, isHost
|
|||
{sortedPlayers.map((entry, index) => (
|
||||
<Cell
|
||||
key={`cell-${index}`}
|
||||
fill={entry.id.startsWith('host') ? '#46178f' : '#8884d8'}
|
||||
fill={entry.color}
|
||||
className="filter drop-shadow-md"
|
||||
/>
|
||||
))}
|
||||
|
|
|
|||
15
constants.ts
15
constants.ts
|
|
@ -23,3 +23,18 @@ export const BOT_NAMES = [
|
|||
|
||||
export const QUESTION_TIME = 20; // seconds
|
||||
export const POINTS_PER_QUESTION = 1000;
|
||||
|
||||
export const PLAYER_COLORS = [
|
||||
'#46178f',
|
||||
'#e21b3c',
|
||||
'#1368ce',
|
||||
'#26890c',
|
||||
'#ffa602',
|
||||
'#d89e00',
|
||||
'#0aa3a3',
|
||||
'#b8008a',
|
||||
'#6a4c93',
|
||||
'#ff6b6b',
|
||||
'#4ecdc4',
|
||||
'#45b7d1',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { Quiz, Player, GameState, GameRole, NetworkMessage, AnswerOption, Question } from '../types';
|
||||
import { generateQuiz } from '../services/geminiService';
|
||||
import { POINTS_PER_QUESTION, QUESTION_TIME } from '../constants';
|
||||
import { POINTS_PER_QUESTION, QUESTION_TIME, PLAYER_COLORS } from '../constants';
|
||||
import { Peer, DataConnection } from 'peerjs';
|
||||
|
||||
export const useGame = () => {
|
||||
|
|
@ -19,6 +19,8 @@ export const useGame = () => {
|
|||
const [selectedOption, setSelectedOption] = useState<AnswerOption | null>(null);
|
||||
const [currentPlayerScore, setCurrentPlayerScore] = useState(0);
|
||||
const [currentStreak, setCurrentStreak] = useState(0);
|
||||
const [currentPlayerId, setCurrentPlayerId] = useState<string | null>(null);
|
||||
const [currentPlayerName, setCurrentPlayerName] = useState<string | null>(null);
|
||||
|
||||
const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||
const peerRef = useRef<Peer | null>(null);
|
||||
|
|
@ -71,20 +73,23 @@ export const useGame = () => {
|
|||
const pin = generateGamePin();
|
||||
setGamePin(pin);
|
||||
|
||||
const peer = new Peer(`openhoot-${pin}`);
|
||||
const peer = new Peer(`kaboot-${pin}`);
|
||||
peerRef.current = peer;
|
||||
|
||||
peer.on('open', (id) => {
|
||||
const hostPlayer: Player = {
|
||||
id: 'host',
|
||||
name: 'Host (You)',
|
||||
name: 'Host',
|
||||
score: 0,
|
||||
streak: 0,
|
||||
lastAnswerCorrect: null,
|
||||
isBot: false,
|
||||
avatarSeed: Math.random()
|
||||
avatarSeed: Math.random(),
|
||||
color: PLAYER_COLORS[0]
|
||||
};
|
||||
setPlayers([hostPlayer]);
|
||||
setCurrentPlayerId('host');
|
||||
setCurrentPlayerName('Host');
|
||||
setGameState('LOBBY');
|
||||
});
|
||||
|
||||
|
|
@ -103,21 +108,23 @@ export const useGame = () => {
|
|||
|
||||
const handleHostData = (conn: DataConnection, data: NetworkMessage) => {
|
||||
if (data.type === 'JOIN') {
|
||||
const newPlayer: Player = {
|
||||
id: conn.peer,
|
||||
name: data.payload.name,
|
||||
score: 0,
|
||||
streak: 0,
|
||||
lastAnswerCorrect: null,
|
||||
isBot: false,
|
||||
avatarSeed: Math.random()
|
||||
};
|
||||
setPlayers(prev => {
|
||||
if (prev.find(p => p.id === newPlayer.id)) return prev;
|
||||
if (prev.find(p => p.id === conn.peer)) return prev;
|
||||
const colorIndex = prev.length % PLAYER_COLORS.length;
|
||||
const newPlayer: Player = {
|
||||
id: conn.peer,
|
||||
name: data.payload.name,
|
||||
score: 0,
|
||||
streak: 0,
|
||||
lastAnswerCorrect: null,
|
||||
isBot: false,
|
||||
avatarSeed: Math.random(),
|
||||
color: PLAYER_COLORS[colorIndex]
|
||||
};
|
||||
return [...prev, newPlayer];
|
||||
});
|
||||
connectionsRef.current.set(conn.peer, conn);
|
||||
conn.send({ type: 'WELCOME', payload: { playerId: conn.peer, quizTitle: 'OpenHoot', players: [] } });
|
||||
conn.send({ type: 'WELCOME', payload: { playerId: conn.peer, quizTitle: 'Kaboot', players: [] } });
|
||||
}
|
||||
|
||||
if (data.type === 'ANSWER') {
|
||||
|
|
@ -247,11 +254,13 @@ export const useGame = () => {
|
|||
setRole('CLIENT');
|
||||
setError(null);
|
||||
setGamePin(pin);
|
||||
setCurrentPlayerName(name);
|
||||
const peer = new Peer();
|
||||
peerRef.current = peer;
|
||||
|
||||
peer.on('open', () => {
|
||||
const conn = peer.connect(`openhoot-${pin}`);
|
||||
peer.on('open', (id) => {
|
||||
setCurrentPlayerId(id);
|
||||
const conn = peer.connect(`kaboot-${pin}`);
|
||||
hostConnectionRef.current = conn;
|
||||
conn.on('open', () => {
|
||||
conn.send({ type: 'JOIN', payload: { name } });
|
||||
|
|
@ -369,7 +378,7 @@ export const useGame = () => {
|
|||
}, []);
|
||||
|
||||
return {
|
||||
role, gameState, quiz, players, currentQuestionIndex, timeLeft, error, gamePin, hasAnswered, lastPointsEarned, currentCorrectShape, selectedOption, currentPlayerScore, currentStreak,
|
||||
role, gameState, quiz, players, currentQuestionIndex, timeLeft, error, gamePin, hasAnswered, lastPointsEarned, currentCorrectShape, selectedOption, currentPlayerScore, currentStreak, currentPlayerId,
|
||||
startQuizGen, startManualCreation, finalizeManualQuiz, joinGame, startGame: startHostGame, handleAnswer, nextQuestion
|
||||
};
|
||||
};
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>OpenHoot</title>
|
||||
<title>Kaboot</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@300;400;600;700&family=Montserrat:wght@400;700;900&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
|
|
|||
2
tasks.md
2
tasks.md
|
|
@ -1,4 +1,4 @@
|
|||
# OpenHoot Development Task List
|
||||
# Kaboot Development Task List
|
||||
|
||||
## Core Setup
|
||||
- [x] Initialize project structure (React, TypeScript, Vite-like setup)
|
||||
|
|
|
|||
1
types.ts
1
types.ts
|
|
@ -39,6 +39,7 @@ export interface Player {
|
|||
lastAnswerCorrect: boolean | null;
|
||||
isBot: boolean;
|
||||
avatarSeed: number;
|
||||
color: string;
|
||||
}
|
||||
|
||||
// Network Types
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue