Added Editor Game and Wall Display
This commit is contained in:
@@ -6,10 +6,10 @@
|
||||
isMultipleChoiceQuestion,
|
||||
isSimpleQuestion,
|
||||
isImageQuestion,
|
||||
type Game,
|
||||
isAudioQuestion,
|
||||
isAudioMultipleChoiceQuestion,
|
||||
isImageMultipleChoiceQuestion
|
||||
isImageMultipleChoiceQuestion,
|
||||
type FullGame
|
||||
} from "$lib/games/games";
|
||||
import ws from "$lib/websocket.svelte";
|
||||
import { page } from "$app/state";
|
||||
@@ -57,7 +57,7 @@
|
||||
|
||||
class GameManager {
|
||||
public state: GameState = $state(GameState.INIT);
|
||||
public game: Game;
|
||||
public game: FullGame;
|
||||
public players: Player[] = $state([
|
||||
{
|
||||
name: "Player 1",
|
||||
@@ -83,7 +83,7 @@
|
||||
public questionIsShowing = $state(false);
|
||||
public isBuzzed = $state(false);
|
||||
|
||||
constructor(game: Game) {
|
||||
constructor(game: FullGame) {
|
||||
this.game = game;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,11 +79,13 @@
|
||||
</script>
|
||||
|
||||
<div class="flex h-full flex-col">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="mr-4 flex items-center gap-4">
|
||||
<h1 class="m-4 mb-8 text-7xl font-bold">Editor</h1>
|
||||
<button class="btn" type="button" onclick={() => (showNewGame = true)}
|
||||
><i class="fa-solid fa-plus"></i> Neues Spiel</button
|
||||
>
|
||||
<div class="grow"></div>
|
||||
<button class="btn" type="button" onclick={() => goto("/")}>Zurück</button>
|
||||
</div>
|
||||
{#if games.length > 0}
|
||||
<div class="flex flex-col space-y-4 overflow-y-auto">
|
||||
|
||||
192
src/routes/editor/[gameid]/+page.svelte
Normal file
192
src/routes/editor/[gameid]/+page.svelte
Normal file
@@ -0,0 +1,192 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import { page } from "$app/state";
|
||||
import Modal from "$lib/Modal.svelte";
|
||||
import Textfield from "$lib/Textfield.svelte";
|
||||
import type { Game, Wall as WallType } from "$lib/Types";
|
||||
import { url } from "$lib/util";
|
||||
import Wall from "$lib/Wall.svelte";
|
||||
import axios from "axios";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let game: Game | undefined = $state();
|
||||
|
||||
let walls: WallType[] = $state([]);
|
||||
let selectedWall: WallType | undefined = $state();
|
||||
|
||||
let showNewWall = $state(false);
|
||||
let newWallName = $state("");
|
||||
|
||||
let showDeleteWall = $state(false);
|
||||
let wallToDelete: WallType | undefined = $state();
|
||||
|
||||
let error = $state("");
|
||||
|
||||
function fetchGame() {
|
||||
return axios
|
||||
.get(url(`/game?id=${page.params.gameid}`), { withCredentials: true })
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
game = response.data;
|
||||
} else {
|
||||
console.error(`Failed to fetch game: ${response.status}`);
|
||||
}
|
||||
})
|
||||
.catch((err) => console.error(err));
|
||||
}
|
||||
|
||||
function fetchWalls() {
|
||||
return axios
|
||||
.get(url(`/walls/${page.params.gameid}`), { withCredentials: true })
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
walls = response.data;
|
||||
if (selectedWall === undefined && walls.length > 0) selectedWall = walls[0];
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
async function addNewWall() {
|
||||
if (!newWallName) return false;
|
||||
return axios
|
||||
.post(
|
||||
url(`/wall`),
|
||||
{
|
||||
gameid: page.params.gameid,
|
||||
name: newWallName
|
||||
},
|
||||
{
|
||||
withCredentials: true
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
newWallName = "";
|
||||
fetchWalls();
|
||||
return true;
|
||||
} else return false;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function addNewWallCancel() {
|
||||
newWallName = "";
|
||||
}
|
||||
|
||||
async function deleteWall() {
|
||||
if (!wallToDelete) return false;
|
||||
if (wallToDelete._id === selectedWall?._id) selectedWall = undefined;
|
||||
return axios
|
||||
.delete(url(`/wall/${wallToDelete._id}`), { withCredentials: true })
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
wallToDelete = undefined;
|
||||
fetchWalls();
|
||||
return true;
|
||||
} else return false;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function deleteWallCancel() {
|
||||
wallToDelete = undefined;
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
fetchGame().then(() => fetchWalls());
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex h-full flex-col">
|
||||
<div class="mr-4 flex items-center gap-4">
|
||||
<h1 class="m-4 text-4xl font-bold">{game ? game.name : "Spiel"}</h1>
|
||||
<div class="grow"></div>
|
||||
<button class="btn" type="button" onclick={() => goto("/editor")}>Zurück</button>
|
||||
</div>
|
||||
<div class="flex grow">
|
||||
<!-- Sidebar -->
|
||||
<div class="flex h-full max-w-[600px] min-w-[400px] flex-col gap-4 border-r-1">
|
||||
<div>
|
||||
<button class="btn ms-4 me-4" type="button" onclick={() => (showNewWall = true)}
|
||||
>Wand hinzufügen</button
|
||||
>
|
||||
</div>
|
||||
{#each walls as wall}
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class="ms-4 me-4 flex items-center justify-between rounded-xl border-2 p-2 hover:cursor-pointer hover:bg-emerald-200"
|
||||
class:bg-emerald-200={selectedWall?._id === wall._id}
|
||||
onclick={() => {
|
||||
selectedWall = wall;
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
{wall.name}
|
||||
</div>
|
||||
<!-- svelte-ignore a11y_consider_explicit_label -->
|
||||
<button
|
||||
type="button"
|
||||
class="btn border-red-600 text-red-600"
|
||||
onclick={(event) => {
|
||||
event.stopPropagation();
|
||||
wallToDelete = wall;
|
||||
showDeleteWall = true;
|
||||
}}><i class="fa-solid fa-trash"></i></button
|
||||
>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<!-- Wall -->
|
||||
{#if selectedWall}
|
||||
<div class="ms-4 me-4 grow">
|
||||
<Wall
|
||||
wall={selectedWall}
|
||||
visited={[]}
|
||||
onclickIds={(catId, queId) => {
|
||||
console.log(catId, queId);
|
||||
if (selectedWall)
|
||||
goto(
|
||||
`/editor/${page.params.gameid}/${selectedWall._id}/${catId}/${queId}`
|
||||
);
|
||||
}}
|
||||
></Wall>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Modal bind:showModal={showNewWall} okFn={addNewWall} cancelFn={addNewWallCancel}>
|
||||
{#snippet header()}
|
||||
<h2 class="text-3xl">Neue Wand</h2>
|
||||
{/snippet}
|
||||
<div>
|
||||
<label for="directory" class="">Name</label>
|
||||
<div>
|
||||
<Textfield bind:value={newWallName}></Textfield>
|
||||
</div>
|
||||
{#if error.length > 0}
|
||||
<div class="text-red-700">{error}</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<Modal bind:showModal={showDeleteWall} okFn={deleteWall} cancelFn={deleteWallCancel}>
|
||||
{#snippet header()}
|
||||
<h2 class="text-3xl">Wand löschen</h2>
|
||||
{/snippet}
|
||||
|
||||
<div>Soll die Wand {wallToDelete?.name} wirklich gelöscht werden?</div>
|
||||
{#if error.length > 0}
|
||||
<div class="text-red-700">{error}</div>
|
||||
{/if}
|
||||
</Modal>
|
||||
15
src/routes/editor/[gameid]/EditorSimpleQuestion.svelte
Normal file
15
src/routes/editor/[gameid]/EditorSimpleQuestion.svelte
Normal file
@@ -0,0 +1,15 @@
|
||||
<script lang="ts">
|
||||
import type { SimpleQuestion } from "$lib/games/games";
|
||||
import Textfield from "$lib/Textfield.svelte";
|
||||
|
||||
interface Props {
|
||||
question: SimpleQuestion;
|
||||
}
|
||||
|
||||
let { question }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<Textfield bind:value={question.data.question}></Textfield>
|
||||
<Textfield bind:value={question.data.answer}></Textfield>
|
||||
</div>
|
||||
Reference in New Issue
Block a user