Updates and more
This commit is contained in:
33
src/components/dashboard/SchematicInfo.svelte
Normal file
33
src/components/dashboard/SchematicInfo.svelte
Normal file
@@ -0,0 +1,33 @@
|
||||
<script lang="ts">
|
||||
import {t} from "astro-i18n"
|
||||
import {createEventDispatcher} from "svelte";
|
||||
import {schemRepo} from "../repo/repo.ts";
|
||||
import {Modal, Spinner} from "flowbite-svelte";
|
||||
import {astroI18n} from "astro-i18n";
|
||||
import moment from "moment/moment";
|
||||
import {CheckSolid, XCircleOutline} from "flowbite-svelte-icons";
|
||||
import SchematicInfoModal from "./SchematicInfoModal.svelte";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let schematicId: number;
|
||||
|
||||
let schemInfo = getSchematicInfo(schematicId);
|
||||
|
||||
function getSchematicInfo(id: number) {
|
||||
return $schemRepo.getSchematicInfo(id);
|
||||
}
|
||||
</script>
|
||||
|
||||
{#await schemInfo}
|
||||
<Modal title="Loading" open on:close={() => dispatch("reset")}>
|
||||
<Spinner />
|
||||
</Modal>
|
||||
{:then info}
|
||||
<SchematicInfoModal {info} on:reset />
|
||||
{:catch e}
|
||||
<Modal title="Error" open on:close={() => dispatch("reset")}>
|
||||
<p>{e.message}</p>
|
||||
<button class="btn !ml-auto" slot="footer" on:click={() => dispatch("reset")}>Close</button>
|
||||
</Modal>
|
||||
{/await}
|
||||
56
src/components/dashboard/SchematicInfoModal.svelte
Normal file
56
src/components/dashboard/SchematicInfoModal.svelte
Normal file
@@ -0,0 +1,56 @@
|
||||
<script lang="ts">
|
||||
import {astroI18n, t} from "astro-i18n";
|
||||
import moment from "moment";
|
||||
import {CheckSolid, XCircleOutline} from "flowbite-svelte-icons";
|
||||
import {Modal} from "flowbite-svelte";
|
||||
import type {SchematicInfo} from "../types/schem.ts";
|
||||
import {createEventDispatcher} from "svelte";
|
||||
import {schemRepo} from "../repo/repo.ts";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let info: SchematicInfo;
|
||||
|
||||
async function download() {
|
||||
const code = await $schemRepo.createDownload(info.schem.id);
|
||||
window.open(import.meta.env.PUBLIC_API_SERVER + "/download/" + code.code, "_blank")
|
||||
dispatch("reset")
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal title={info.schem.name} autoclose open on:close={() => dispatch("reset")}>
|
||||
<p>{t("dashboard.schematic.info.path", {path: info.path})}</p>
|
||||
<p class="flex !mt-0">
|
||||
{t("dashboard.schematic.info.replaceColor")}
|
||||
{#if info.schem.replaceColor}
|
||||
<CheckSolid class="text-green-500 ml-2" />
|
||||
{:else}
|
||||
<XCircleOutline class="text-red-500 ml-2" />
|
||||
{/if}
|
||||
</p>
|
||||
<p class="flex !mt-0">
|
||||
{t("dashboard.schematic.info.allowReplay")}
|
||||
{#if info.schem.allowReplay}
|
||||
<CheckSolid class="text-green-500 ml-2" />
|
||||
{:else}
|
||||
<XCircleOutline class="text-red-500 ml-2" />
|
||||
{/if}
|
||||
</p>
|
||||
<p class="!mt-0">{t("dashboard.schematic.info.type", {type: info.schem.type ?? t("dashboard.schematic.dir")})}</p>
|
||||
<p class="!mt-0">{t("dashboard.schematic.info.updated", {updated: new Intl.DateTimeFormat(astroI18n.locale, {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
year: "numeric"
|
||||
}).format(moment(info.schem.lastUpdate).utc(false).toDate())})}</p>
|
||||
<p class="!mt-0">{t("dashboard.schematic.info.item", {item: info.schem.item ?? (info.schem.type == null ? "CHEST" : "CAULDRON_ITEM")})}</p>
|
||||
{#if info.members.length !== 0}
|
||||
<p class="!mt-0">{t("dashboard.schematic.info.members", {members: info.members.join(", ")})}</p>
|
||||
{/if}
|
||||
<svelte:fragment slot="footer">
|
||||
<button class="btn !ml-auto" on:click={download}>{t("dashboard.schematic.info.btn.download")}</button>
|
||||
<button class="btn" on:click={() => dispatch("reset")}>{t("dashboard.schematic.info.btn.close")}</button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
115
src/components/dashboard/SchematicList.svelte
Normal file
115
src/components/dashboard/SchematicList.svelte
Normal file
@@ -0,0 +1,115 @@
|
||||
<script lang="ts">
|
||||
import {t} from "astro-i18n";
|
||||
import {ChevronDoubleRightOutline, FolderOutline, HomeOutline, InfoCircleOutline} from "flowbite-svelte-icons";
|
||||
import SchematicListTile from "./SchematicListTile.svelte";
|
||||
import {Breadcrumb, BreadcrumbItem, Tooltip} from "flowbite-svelte";
|
||||
import {createEventDispatcher} from "svelte";
|
||||
import type {SchematicList} from "../types/schem.ts";
|
||||
import SchematicInfo from "./SchematicInfo.svelte";
|
||||
import UploadModal from "./UploadModal.svelte";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let schematics: SchematicList;
|
||||
|
||||
let uploadOpen = false;
|
||||
let infoModalId: number | null = null;
|
||||
|
||||
function schemListClick(isDir: boolean, id: number) {
|
||||
if (isDir) {
|
||||
return () => dispatch("to", {id})
|
||||
} else {
|
||||
return () => infoModalId = id
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex justify-between">
|
||||
<Breadcrumb navClass="py-4">
|
||||
<BreadcrumbItem home>
|
||||
<svelte:fragment slot="icon">
|
||||
<HomeOutline class="w-6 h-6 mx-2 dark:text-white" />
|
||||
</svelte:fragment>
|
||||
<span on:click={() => dispatch("reset")} class="hover:underline hover:cursor-pointer text-2xl">{t("dashboard.schematic.home")}</span>
|
||||
</BreadcrumbItem>
|
||||
{#each schematics.breadcrumbs as bread}
|
||||
<BreadcrumbItem>
|
||||
<svelte:fragment slot="icon">
|
||||
<ChevronDoubleRightOutline class="w-4 h-4 mx-2 dark:text-white" />
|
||||
</svelte:fragment>
|
||||
<span on:click={() => dispatch("to", {id: bread.id})} class="hover:underline hover:cursor-pointer text-2xl">{bread.name}</span>
|
||||
</BreadcrumbItem>
|
||||
{/each}
|
||||
</Breadcrumb>
|
||||
<div class="flex flex-col justify-center">
|
||||
<button class="btn" on:click={() => uploadOpen = true}>
|
||||
{t("dashboard.schematic.upload")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr class="!cursor-auto">
|
||||
<th>{t("dashboard.schematic.head.type")}</th>
|
||||
<th>{t("dashboard.schematic.head.name")}</th>
|
||||
<th class="hidden sm:table-cell">{t("dashboard.schematic.head.owner")}</th>
|
||||
<th class="hidden sm:table-cell"></th>
|
||||
<th class="hidden md:table-cell">{t("dashboard.schematic.head.updated")}</th>
|
||||
<th>
|
||||
<InfoCircleOutline />
|
||||
<Tooltip>
|
||||
<span>{t("dashboard.schematic.head.replaceColor")}</span>
|
||||
</Tooltip>
|
||||
</th>
|
||||
<th>
|
||||
<InfoCircleOutline />
|
||||
<Tooltip>
|
||||
<span>{t("dashboard.schematic.head.allowReplay")}</span>
|
||||
</Tooltip>
|
||||
</th>
|
||||
</tr>
|
||||
{#if schematics.breadcrumbs.length !== 0}
|
||||
<tr on:click|preventDefault={() => {
|
||||
if (schematics.breadcrumbs.length === 1) {
|
||||
dispatch("reset")
|
||||
} else {
|
||||
dispatch("to", {id: schematics.breadcrumbs[schematics.breadcrumbs.length - 2].id})
|
||||
}
|
||||
}}>
|
||||
<th>
|
||||
<FolderOutline />
|
||||
</th>
|
||||
<th>../</th>
|
||||
<th class="hidden sm:table-cell"></th>
|
||||
<th class="hidden sm:table-cell">{t("dashboard.schematic.dir")}</th>
|
||||
<th class="hidden md:table-cell"></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{/if}
|
||||
{#each schematics.schematics as schem}
|
||||
<SchematicListTile schem={schem} players={schematics.players} on:click={schemListClick(schem.type == null, schem.id)} />
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<UploadModal bind:open={uploadOpen} on:refresh />
|
||||
|
||||
{#if infoModalId !== null}
|
||||
<SchematicInfo schematicId={infoModalId} on:reset={() => infoModalId = null} />
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
table {
|
||||
@apply w-full;
|
||||
}
|
||||
|
||||
tr {
|
||||
@apply transition-colors cursor-pointer border-b
|
||||
dark:hover:bg-gray-800 hover:bg-gray-300;
|
||||
}
|
||||
|
||||
th {
|
||||
@apply text-left py-4 md:px-2;
|
||||
}
|
||||
</style>
|
||||
58
src/components/dashboard/SchematicListTile.svelte
Normal file
58
src/components/dashboard/SchematicListTile.svelte
Normal file
@@ -0,0 +1,58 @@
|
||||
<script lang="ts">
|
||||
import {astroI18n, t} from "astro-i18n";
|
||||
import moment from "moment/moment.js";
|
||||
import {CheckSolid, FileOutline, FolderOutline, XCircleOutline} from "flowbite-svelte-icons";
|
||||
import type {Schematic} from "../types/schem.ts";
|
||||
import type {Player} from "../types/data.ts";
|
||||
|
||||
export let schem: Schematic;
|
||||
export let players: Record<number, Player>;
|
||||
</script>
|
||||
|
||||
<tr on:click|preventDefault>
|
||||
<th>
|
||||
{#if schem.type == null}
|
||||
<FolderOutline />
|
||||
{:else}
|
||||
<FileOutline />
|
||||
{/if}
|
||||
</th>
|
||||
<th>
|
||||
{schem.name}{#if schem.type == null}/{/if}
|
||||
</th>
|
||||
<th class="hidden sm:table-cell">{players[schem.owner].name}</th>
|
||||
<th class="hidden sm:table-cell">{schem.type ?? t("dashboard.schematic.dir")}</th>
|
||||
<th class="hidden md:table-cell">{new Intl.DateTimeFormat(astroI18n.locale, {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
year: "numeric"
|
||||
}).format(moment(schem.lastUpdate).utc(false).toDate())}</th>
|
||||
<th>
|
||||
{#if schem.replaceColor}
|
||||
<CheckSolid class="text-green-500" />
|
||||
{:else}
|
||||
<XCircleOutline class="text-red-500" />
|
||||
{/if}
|
||||
</th>
|
||||
<th>
|
||||
{#if schem.allowReplay}
|
||||
<CheckSolid class="text-green-500" />
|
||||
{:else}
|
||||
<XCircleOutline class="text-red-500" />
|
||||
{/if}
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
<style lang="scss">
|
||||
tr {
|
||||
@apply transition-colors cursor-pointer border-b
|
||||
dark:hover:bg-gray-800 hover:bg-gray-300;
|
||||
}
|
||||
|
||||
th {
|
||||
@apply text-left py-4 md:px-2;
|
||||
}
|
||||
</style>
|
||||
47
src/components/dashboard/UploadModal.svelte
Normal file
47
src/components/dashboard/UploadModal.svelte
Normal file
@@ -0,0 +1,47 @@
|
||||
<script lang="ts">
|
||||
import {Modal} from "flowbite-svelte";
|
||||
import {schemRepo} from "../repo/repo.js";
|
||||
import {createEventDispatcher} from "svelte";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let open = false;
|
||||
|
||||
async function upload() {
|
||||
if (uploadFile == null) {
|
||||
return
|
||||
}
|
||||
let file = uploadFile[0];
|
||||
|
||||
let name = file.name;
|
||||
|
||||
let type = name.split(".").pop();
|
||||
|
||||
if (type !== "schem" && type !== "schematic") {
|
||||
return
|
||||
}
|
||||
|
||||
let content = await file.arrayBuffer();
|
||||
|
||||
// @ts-ignore
|
||||
let b64 = btoa(String.fromCharCode.apply(null, new Uint8Array(content)));
|
||||
|
||||
await $schemRepo.uploadSchematic(name, b64);
|
||||
|
||||
open = false;
|
||||
uploadFile = null;
|
||||
dispatch("reset")
|
||||
}
|
||||
|
||||
let uploadFile: File[] | null = null;
|
||||
</script>
|
||||
|
||||
<Modal title="Upload Schematic" bind:open autoclose outsideclose>
|
||||
<form>
|
||||
<input type="file" bind:files={uploadFile} />
|
||||
</form>
|
||||
<svelte:fragment slot="footer">
|
||||
<button class="btn !ml-auto" on:click={upload}>Upload</button>
|
||||
<button class="btn btn-gray" on:click={() => open = false}>Close</button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
41
src/components/dashboard/UserInfo.svelte
Normal file
41
src/components/dashboard/UserInfo.svelte
Normal file
@@ -0,0 +1,41 @@
|
||||
<script lang="ts">
|
||||
import {t} from "astro-i18n";
|
||||
import type {Player} from "../types/data.ts";
|
||||
import {tokenStore} from "../repo/repo.ts";
|
||||
import {l} from "../../util/util.ts";
|
||||
|
||||
export let user: Player;
|
||||
|
||||
function logout() {
|
||||
tokenStore.set("")
|
||||
window.location.href = l("/login")
|
||||
}
|
||||
</script>
|
||||
<div class="flex mb-4 flex-col md:flex-row">
|
||||
<div>
|
||||
<div class="bg-zinc-50 border-gray-100 py-24 px-12 border-2 m-2 transition duration-300 ease-in-out rounded-xl shadow-lg hidden md:block
|
||||
hover:scale-105 hover:shadow-2xl
|
||||
dark:bg-neutral-900 dark:border-gray-800 dark:text-white">
|
||||
<figure>
|
||||
<figcaption class="text-center mb-4 text-2xl">{user.name}</figcaption>
|
||||
<img src={`https://visage.surgeplay.com/bust/150/${user.uuid}`} class="transition duration-300 ease-in-out hover:scale-110 hover:drop-shadow-2xl" alt={user.name + "s bust"} width="150" height="150" />
|
||||
</figure>
|
||||
</div>
|
||||
<div class="flex flex-wrap">
|
||||
<button class="btn mt-2" on:click={logout}>{t("dashboard.buttons.logout")}</button>
|
||||
{#if user.perms.includes("MODERATION")}
|
||||
<a class="btn w-fit mt-2" href="/admin">{t("dashboard.buttons.admin")}</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-4xl font-bold">{t("dashboard.title", {name: user.name})}</h1>
|
||||
<p>{t("dashboard.rank", {rank: t("home.prefix." + user.prefix)})}</p>
|
||||
<p>{t("dashboard.permissions")}</p>
|
||||
<ul>
|
||||
{#each user.perms as permission}
|
||||
<li class="list-disc ml-6">{permission}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user