Editor: added game creation and deletion

This commit is contained in:
2025-12-28 12:51:43 +01:00
parent 48bc66b89a
commit daf3f779aa
4 changed files with 199 additions and 3 deletions

View File

@@ -27,6 +27,9 @@
let showDeleteDir = $state(false); let showDeleteDir = $state(false);
let dirToDelete: Directory | undefined = $state(); let dirToDelete: Directory | undefined = $state();
let showDeleteRessource = $state(false);
let resToDelete: Ressource | undefined = $state();
let showRenameFile = $state(false); let showRenameFile = $state(false);
let fileToRename: Ressource | undefined = $state(); let fileToRename: Ressource | undefined = $state();
let newFileName = $state(""); let newFileName = $state("");
@@ -73,23 +76,35 @@
}); });
} }
function deleteRessource(res: Ressource | Directory) { async function deleteRessource(res: Ressource | Directory): Promise<boolean> {
if (isRessource(res)) { if (isRessource(res)) {
axios return axios
.delete(url("/cdn/" + res.user + "/" + res.filename), { .delete(url("/cdn/" + res.user + "/" + res.filename), {
withCredentials: true withCredentials: true
}) })
.then((response) => { .then((response) => {
if (response.status === 200) { if (response.status === 200) {
fetchDirectory(); fetchDirectory();
return true;
} else { } else {
alert("Something went wrong: " + response.status); alert("Something went wrong: " + response.status);
return false;
} }
})
.catch((err) => {
console.error(err);
return false;
}); });
} else if (isDir(res)) { } else if (isDir(res)) {
showDeleteDir = true; showDeleteDir = true;
dirToDelete = res; dirToDelete = res;
return true;
} }
return false;
}
function deleteRessourceCancel() {
resToDelete = undefined;
} }
async function deleteDir() { async function deleteDir() {
@@ -313,7 +328,10 @@
class="btn border-red-600 text-red-600" class="btn border-red-600 text-red-600"
onclick={(event) => { onclick={(event) => {
event.stopPropagation(); event.stopPropagation();
deleteRessource(ressource); if (isRessource(ressource)) {
showDeleteRessource = true;
resToDelete = ressource;
}
}}><i class="fa-solid fa-trash"></i></button }}><i class="fa-solid fa-trash"></i></button
> >
</div> </div>
@@ -365,6 +383,26 @@
</div> </div>
</Modal> </Modal>
<Modal
bind:showModal={showDeleteRessource}
okFn={async () => {
if (resToDelete === undefined) return false;
return deleteRessource(resToDelete);
}}
cancelFn={deleteRessourceCancel}
>
{#snippet header()}
<h2 class="text-3xl">Ressource löschen</h2>
{/snippet}
<div>
Soll die Ressource {resToDelete?.name} wirklich gelöscht werden?
</div>
{#if error.length > 0}
<div class="text-red-700">{error}</div>
{/if}
</Modal>
<Modal bind:showModal={showDeleteDir} okFn={deleteDir} cancelFn={deleteDirCancel}> <Modal bind:showModal={showDeleteDir} okFn={deleteDir} cancelFn={deleteDirCancel}>
{#snippet header()} {#snippet header()}
<h2 class="text-3xl">Ordner löschen</h2> <h2 class="text-3xl">Ordner löschen</h2>

View File

@@ -22,3 +22,14 @@ export function isDir(dir: Directory | Ressource): dir is Directory {
export function isRessource(ressource: Ressource | Directory): ressource is Ressource { export function isRessource(ressource: Ressource | Directory): ressource is Ressource {
return (ressource as Directory).isDir === undefined; return (ressource as Directory).isDir === undefined;
} }
export type GameId = string;
export type Game = {
name: string;
owner: string;
_id: GameId;
walls: WallId[];
};
export type WallId = string;

View File

@@ -59,6 +59,7 @@
<button type="button" class="btn" onclick={() => (showRessourceManager = true)} <button type="button" class="btn" onclick={() => (showRessourceManager = true)}
>Ressourcen</button >Ressourcen</button
> >
<button type="button" class="btn" onclick={() => goto("/editor")}>Editor</button>
<button type="button" class="btn" onclick={() => goto("/settings")}>Einstellungen</button> <button type="button" class="btn" onclick={() => goto("/settings")}>Einstellungen</button>
<button type="button" class="btn" onclick={logoutFromAllDevices}>Logout</button> <button type="button" class="btn" onclick={logoutFromAllDevices}>Logout</button>
<div class="btn profile ps-2 pe-2"> <div class="btn profile ps-2 pe-2">

View File

@@ -0,0 +1,146 @@
<script lang="ts">
import Modal from "$lib/Modal.svelte";
import type { Game } from "$lib/Types";
import { url } from "$lib/util";
import axios from "axios";
import { onMount } from "svelte";
let games: Game[] = $state([]);
let error = $state("");
let showNewGame = $state(false);
let newGameName = $state("");
let showDeleteGame = $state(false);
let gameToDelete: Game | undefined = $state();
async function addNewGame() {
if (!newGameName) return false;
return axios
.post(url("game"), { name: newGameName }, { withCredentials: true })
.then((response) => {
if (response.status === 200) {
fetchGames();
newGameName = "";
return true;
} else return false;
});
}
function addNewGameCancel() {
newGameName = "";
}
async function deleteGame() {
if (gameToDelete === undefined) return false;
return axios
.delete(url("/game/" + gameToDelete._id), { withCredentials: true })
.then((response) => {
if (response.status === 200) {
fetchGames();
gameToDelete = undefined;
return true;
} else {
console.error("Failed to delete Game: " + response.status);
return false;
}
})
.catch((err) => {
console.error(err);
return false;
});
}
function deleteGameCancel() {
gameToDelete = undefined;
}
function fetchGames() {
axios
.get(url("games"), { withCredentials: true })
.then((response) => {
if (response.status === 200) {
games = response.data;
} else {
console.error("Could not fetch games: " + response.status);
}
})
.catch((err) => {
console.error(err);
});
}
onMount(() => {
fetchGames();
});
</script>
<div class="flex h-full flex-col">
<div class="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>
<div class="flex flex-col space-y-4 overflow-y-auto">
{#each games as game}
<div
class="ms-4 me-4 flex items-center justify-between rounded-xl border-2 p-2 hover:cursor-pointer hover:bg-emerald-200"
>
<a class="" href={`${game._id}`}>{game.name}</a>
<!-- svelte-ignore a11y_consider_explicit_label -->
<button
type="button"
class="btn border-red-600 text-red-600"
onclick={(event) => {
event.stopPropagation();
gameToDelete = game;
showDeleteGame = true;
}}><i class="fa-solid fa-trash"></i></button
>
</div>
{/each}
</div>
</div>
<Modal bind:showModal={showNewGame} okFn={addNewGame} cancelFn={addNewGameCancel}>
{#snippet header()}
<h2 class="text-3xl">Neues Spiel</h2>
{/snippet}
<div>
<label for="directory" class="">Name</label>
<div>
<input
type="text"
name="directory"
id="directory"
class="borders mt-2 mb-2 w-full"
bind:value={newGameName}
/>
</div>
{#if error.length > 0}
<div class="text-red-700">{error}</div>
{/if}
</div>
</Modal>
<Modal bind:showModal={showDeleteGame} okFn={deleteGame} cancelFn={deleteGameCancel}>
{#snippet header()}
<h2 class="text-3xl">Spiel löschen</h2>
{/snippet}
<div>Soll das Spiel {gameToDelete?.name} wirklich gelöscht werden?</div>
{#if error.length > 0}
<div class="text-red-700">{error}</div>
{/if}
</Modal>
<style>
.borders {
border: 1px solid black;
border-radius: 5px;
display: flex;
padding: 2px;
}
</style>