Almost done
This commit is contained in:
58
src/lib/DisplayState.svelte.ts
Normal file
58
src/lib/DisplayState.svelte.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import type { Game, Wall } from "./games/games";
|
||||
|
||||
interface Player {
|
||||
name: string;
|
||||
points: number;
|
||||
}
|
||||
|
||||
const baseRoute = "/connected/display/running";
|
||||
let players: Player[] = $state([]);
|
||||
let currentPlayer: string = $state("");
|
||||
// eslint-disable-next-line prefer-const
|
||||
let game: Game | undefined = undefined;
|
||||
let gameIndex: number = -1;
|
||||
let wall: Wall | undefined = undefined;
|
||||
let wallIndex: number = -1;
|
||||
|
||||
export default {
|
||||
get players(): Player[] {
|
||||
return players;
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
set players(newPlayers: any) {
|
||||
players = newPlayers;
|
||||
},
|
||||
get currentPlayer(): string {
|
||||
return currentPlayer;
|
||||
},
|
||||
set currentPlayer(str: string) {
|
||||
currentPlayer = str;
|
||||
},
|
||||
baseRoute,
|
||||
get game(): Game | undefined {
|
||||
return game;
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
set game(newGame: any) {
|
||||
game = newGame;
|
||||
},
|
||||
get gameIndex() {
|
||||
return gameIndex;
|
||||
},
|
||||
set gameIndex(i: number) {
|
||||
gameIndex = i;
|
||||
},
|
||||
get wall(): Wall | undefined {
|
||||
return wall;
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
set wall(newWall: any) {
|
||||
wall = newWall;
|
||||
},
|
||||
get wallIndex() {
|
||||
return wallIndex;
|
||||
},
|
||||
set wallIndex(i: number) {
|
||||
wallIndex = i;
|
||||
}
|
||||
};
|
||||
10
src/lib/GameState.svelte.ts
Normal file
10
src/lib/GameState.svelte.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
let displayConnected = $state(false);
|
||||
|
||||
export default {
|
||||
get displayConnected() {
|
||||
return displayConnected;
|
||||
},
|
||||
set displayConnected(c: boolean) {
|
||||
displayConnected = c;
|
||||
}
|
||||
};
|
||||
6
src/lib/GameState.ts
Normal file
6
src/lib/GameState.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export enum GameState {
|
||||
INIT,
|
||||
CHOOSING_QUESTION,
|
||||
SHOW_QUESTION,
|
||||
END
|
||||
}
|
||||
8
src/lib/MessageType.ts
Normal file
8
src/lib/MessageType.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export enum MessageType {
|
||||
START = "START",
|
||||
PLAYERS = "PLAYERS",
|
||||
GOTO = "GOTO",
|
||||
SHOW_ANSWER = "SHOW_ANSWER",
|
||||
HIDE_ANSWER = "HIDE_ANSWER",
|
||||
VISITED_QUESTIONS = "VISITED_QUESTIONS"
|
||||
}
|
||||
4
src/lib/Player.ts
Normal file
4
src/lib/Player.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface Player {
|
||||
name: string;
|
||||
points: number;
|
||||
}
|
||||
37
src/lib/PlusMinusButton.svelte
Normal file
37
src/lib/PlusMinusButton.svelte
Normal file
@@ -0,0 +1,37 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
label: string;
|
||||
plus: (label: string) => void;
|
||||
minus: (label: string) => void;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
let { label, plus, minus }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="specialBtn flex w-min gap-2 text-2xl">
|
||||
<button class="innerBtn" onclick={() => minus(label)}>-</button>
|
||||
<div class="whitespace-nowrap">
|
||||
{label}
|
||||
</div>
|
||||
<button class="innerBtn" onclick={() => plus(label)}>+</button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.specialBtn {
|
||||
border: 1px solid black;
|
||||
border-radius: 5px;
|
||||
padding: 4px;
|
||||
height: fit-content;
|
||||
align-items: center;
|
||||
}
|
||||
.innerBtn {
|
||||
width: 30px;
|
||||
border-radius: 5px;
|
||||
padding: 4px;
|
||||
}
|
||||
.innerBtn:hover {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
42
src/lib/Scoreboard.svelte
Normal file
42
src/lib/Scoreboard.svelte
Normal file
@@ -0,0 +1,42 @@
|
||||
<script lang="ts">
|
||||
import type { Player } from "./Player";
|
||||
|
||||
interface Props {
|
||||
players: Player[];
|
||||
currentPlayer: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
let { players, currentPlayer }: Props = $props();
|
||||
|
||||
let _players = $derived(() => {
|
||||
let p = [...players];
|
||||
return p.sort((a: Player, b: Player) => b.points - a.points);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="h-full w-fit max-w-[400px] overflow-hidden border-r-1 border-solid border-gray-300 pr-4 pl-4"
|
||||
>
|
||||
<div class="flex justify-center">
|
||||
<h3 class="text-5xl">Scoreboard</h3>
|
||||
</div>
|
||||
<div class="mt-4 text-3xl">
|
||||
<table class="w-1/1">
|
||||
<tbody>
|
||||
{#each _players() as player}
|
||||
<tr class="{currentPlayer === player.name ? 'current' : ''} h-12">
|
||||
<td class="pr-4 pl-2">{player.points}</td>
|
||||
<td>{player.name}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.current {
|
||||
background-color: rgb(166, 255, 165);
|
||||
}
|
||||
</style>
|
||||
22
src/lib/SimpleQuestionComponent.svelte
Normal file
22
src/lib/SimpleQuestionComponent.svelte
Normal file
@@ -0,0 +1,22 @@
|
||||
<script lang="ts">
|
||||
import type { SimpleQuestion } from "./games/games";
|
||||
|
||||
interface Props {
|
||||
question: SimpleQuestion;
|
||||
showAnswer: boolean;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
let { question, showAnswer }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="mb-4 flex grow flex-col items-center text-6xl">
|
||||
<div class="flex grow-1 items-center">
|
||||
<div>{question.data.question}</div>
|
||||
</div>
|
||||
{#if showAnswer}
|
||||
<div class="flex grow-1 items-center">
|
||||
{question.data.answer}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
1
src/lib/Types.ts
Normal file
1
src/lib/Types.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type VisitedQuestions = number[][];
|
||||
49
src/lib/Wall.svelte
Normal file
49
src/lib/Wall.svelte
Normal file
@@ -0,0 +1,49 @@
|
||||
<script lang="ts">
|
||||
import type { Wall } from "$lib/games/games";
|
||||
import type { VisitedQuestions } from "./Types";
|
||||
|
||||
interface Props {
|
||||
wall: Wall | undefined;
|
||||
onclick?: (catIndex: number, questionIndex: number) => unknown;
|
||||
visited: VisitedQuestions;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
function isVisited(catIndex: number, queIndex: number): boolean {
|
||||
return visited[catIndex] && visited[catIndex].includes(queIndex);
|
||||
}
|
||||
|
||||
let { wall, onclick, visited }: Props = $props();
|
||||
</script>
|
||||
|
||||
{#if wall != undefined}
|
||||
<div class="grid h-full grow grid-flow-col grid-cols-5 grid-rows-6 gap-4 pb-4">
|
||||
{#each wall.categories as category, catIndex}
|
||||
<div class="flex items-center justify-center text-3xl font-semibold">
|
||||
<div>{category.name}</div>
|
||||
</div>
|
||||
{#each category.questions as question, queIndex}
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<div
|
||||
class="card {isVisited(catIndex, queIndex) ? 'visited' : ''}"
|
||||
role="button"
|
||||
aria-pressed="false"
|
||||
tabindex="0"
|
||||
onclick={() => {
|
||||
if (onclick) onclick(catIndex, queIndex);
|
||||
}}
|
||||
>
|
||||
<div>{question.points}</div>
|
||||
</div>
|
||||
{/each}
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<p>Wall is undefined</p>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.visited {
|
||||
background-color: gray;
|
||||
}
|
||||
</style>
|
||||
@@ -931,9 +931,11 @@ const games: Games = [
|
||||
}
|
||||
];
|
||||
|
||||
export type QuestionType = "SIMPLE" | "MULTIPLE_CHOICE";
|
||||
|
||||
export type Question = {
|
||||
points: number;
|
||||
type: "SIMPLE" | "MULTIPLE_CHOICE";
|
||||
type: QuestionType;
|
||||
};
|
||||
|
||||
export type SimpleQuestion = Question & {
|
||||
@@ -953,6 +955,13 @@ export type MultipleChoiceQuestion = Question & {
|
||||
};
|
||||
};
|
||||
|
||||
export function isSimpleQuestion(question: Question): question is SimpleQuestion {
|
||||
return (question as SimpleQuestion).type === "SIMPLE";
|
||||
}
|
||||
export function isMultipleChoiceQuestion(question: Question): question is MultipleChoiceQuestion {
|
||||
return (question as MultipleChoiceQuestion).type === "MULTIPLE_CHOICE";
|
||||
}
|
||||
|
||||
export type Category = {
|
||||
name: string;
|
||||
questions: (SimpleQuestion | MultipleChoiceQuestion)[];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export enum SocketConnectionType {
|
||||
NONE,
|
||||
HOST,
|
||||
DISPLAY
|
||||
NONE = "NONE",
|
||||
HOST = "HOST",
|
||||
DISPLAY = "DISPLAY"
|
||||
}
|
||||
|
||||
const messages: string[] = $state([]);
|
||||
@@ -41,7 +41,7 @@ function onOpen(type: SocketConnectionType) {
|
||||
console.log("Connection established");
|
||||
console.log(event);
|
||||
if (socket === undefined) return;
|
||||
socket.send(type == SocketConnectionType.HOST ? "HOST" : "DISPLAY");
|
||||
socket.send(type.toString());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -49,11 +49,11 @@ function onOpen(type: SocketConnectionType) {
|
||||
function onFirstMessage(event: MessageEvent<any>) {
|
||||
if (socket === undefined) return;
|
||||
console.log(event.data);
|
||||
if (event.data === "HOST") {
|
||||
if (event.data === SocketConnectionType.HOST) {
|
||||
connectionType = SocketConnectionType.HOST;
|
||||
socket.removeEventListener("message", onFirstMessage);
|
||||
socket.addEventListener("message", onMessage);
|
||||
} else if (event.data === "DISPLAY") {
|
||||
} else if (event.data === SocketConnectionType.DISPLAY) {
|
||||
connectionType = SocketConnectionType.DISPLAY;
|
||||
socket.removeEventListener("message", onFirstMessage);
|
||||
socket.addEventListener("message", onMessage);
|
||||
|
||||
Reference in New Issue
Block a user