mcgrizz/routes/mods/index.tsx

197 lines
6.2 KiB
TypeScript

import { FunctionComponent } from "preact";
import { Content } from "../../components/Content.tsx";
import { SERVER_STATE } from "../../state/serverState.ts";
import { FileUploader } from "../../islands/fileUploader.tsx";
import { Handlers, PageProps } from "$fresh/server.ts";
import { ensureFile } from "$std/fs/ensure_file.ts";
import { ensureDir } from "$std/fs/ensure_dir.ts";
import { Button } from "../../components/Button.tsx";
export const handler: Handlers = {
async POST(req, _ctx) {
const formData = await req.formData();
const filePath = formData.get("filePath") as string;
if (typeof filePath !== "string") {
throw "File path not included in mod enable/disable";
}
if (formData.get("delete")) {
await Deno.remove(filePath);
return Response.redirect(req.url);
}
const fileName = filePath.split("/").at(-1);
if (!fileName) throw "Unable to infer filename in mod enable/disable";
try {
await Deno.lstat(filePath);
} catch {
return Response.redirect(req.url);
}
if (filePath.includes("disabled")) {
await ensureFile("./server/mods/" + fileName);
await Deno.rename(filePath, "./server/mods/" + fileName);
} else {
await ensureFile("./server/disabled-mods/" + fileName);
await Deno.rename(filePath, "./server/disabled-mods/" + fileName);
}
return Response.redirect(req.url);
},
async GET(_, ctx) {
const activeMods: string[] = [];
const disabledMods: string[] = [];
if (
SERVER_STATE.serverType !== "unset" &&
SERVER_STATE.serverType !== "vanilla"
) {
for await (const fileEntry of Deno.readDir("./server/mods")) {
if (fileEntry.isFile) {
activeMods.push(fileEntry.name);
}
}
await ensureDir("./server/disabled-mods");
for await (const fileEntry of Deno.readDir("./server/disabled-mods")) {
if (fileEntry.isFile) {
disabledMods.push(fileEntry.name);
}
}
}
return ctx.render({
activeMods,
disabledMods,
});
},
};
export default function ModsFolder(
{ url, data: { activeMods, disabledMods } }: PageProps<
{ activeMods: string[]; disabledMods: string[] }
>,
) {
return (
<div className="container p-8 flex flex-col gap-8">
<Content>
<h2 class="font-pixel text-xl">Active Mods</h2>
<FileUploader path="./server/mods">
<div class="min-h-[100px]">
<div className="relative grid lg:grid-cols-3 gap-8">
{!activeMods.length && (
<div class="absolute place-self-center">
Drop files here to upload
</div>
)}
{activeMods.map((f) => (
<div class="flex justify-between">
<div class="flex gap-2 items-center">
<FileIcon fileName={f} />
{f}
</div>
<div class="flex gap-2">
<form action={url.pathname} method="POST">
<input
type="hidden"
name="filePath"
value={"./server/mods/" + f}
/>
<Button type="submit">Disable</Button>
</form>
<form action={url.pathname} method="POST">
<input
type="hidden"
name="filePath"
value={"./server/disabled-mods/" + f}
/>
<input
type="hidden"
name="delete"
value="true"
/>
<Button color="fire" type="submit">
<i class="fas fa-trash"></i>
</Button>
</form>
</div>
</div>
))}
</div>
</div>
</FileUploader>
</Content>
<Content>
<h2 class="font-pixel text-xl">Disabled Mods</h2>
<FileUploader path="./server/disabled-mods">
<div class="min-h-[100px]">
<div className="relative grid lg:grid-cols-3 gap-8">
{!disabledMods.length && (
<div class="absolute place-self-center">
Drop files here to upload
</div>
)}
{disabledMods.map((f) => (
<div class="flex justify-between">
<div class="flex gap-2 items-center">
<FileIcon fileName={f} />
{f}
</div>
<div class="flex gap-2">
<form action={url.pathname} method="POST">
<input
type="hidden"
name="filePath"
value={"./server/disabled-mods/" + f}
/>
<Button type="submit">Enable</Button>
</form>
<form action={url.pathname} method="POST">
<input
type="hidden"
name="filePath"
value={"./server/disabled-mods/" + f}
/>
<input
type="hidden"
name="delete"
value="true"
/>
<Button color="fire" type="submit">
<i class="fas fa-trash"></i>
</Button>
</form>
</div>
</div>
))}
</div>
</div>
</FileUploader>
</Content>
</div>
);
}
const FileIcon: FunctionComponent<{ fileName: string }> = ({ fileName }) => {
let icon;
switch (fileName.split(".").at(-1)) {
case "jar":
icon = "fab fa-java";
break;
case "tmp":
case "temp":
icon = "fas fa-ghost";
break;
case "png":
case "jpg":
case "jpeg":
case "webp":
icon = "fas fa-image";
break;
default:
icon = "fas fa-file";
}
return <i class={icon}></i>;
};