186 lines
5.9 KiB
TypeScript
186 lines
5.9 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);
|
|
},
|
|
};
|
|
|
|
export default async function ModsFolder({ url }: PageProps) {
|
|
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);
|
|
}
|
|
}
|
|
ensureDir("./server/disabled-mods");
|
|
for await (const fileEntry of Deno.readDir("./server/disabled-mods")) {
|
|
if (fileEntry.isFile) {
|
|
disabledMods.push(fileEntry.name);
|
|
}
|
|
}
|
|
}
|
|
|
|
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>;
|
|
};
|