138 lines
4.0 KiB
TypeScript
138 lines
4.0 KiB
TypeScript
import { useEffect, useState } from "preact/hooks";
|
|
import { Modal } from "../components/modal.tsx";
|
|
import { LabelledHr } from "../components/labelledHr.tsx";
|
|
import { PacksList } from "../components/packsList.tsx";
|
|
import { PackInfo } from "../components/packInfo.tsx";
|
|
import { useAtom } from "jotai";
|
|
import { namespaceAtom } from "../atoms/namespace.ts";
|
|
import { Outlet, Route, Routes } from "react-router-dom";
|
|
import { Selector } from "../components/editor/selector.tsx";
|
|
import { NamespaceModal } from "../components/editor/namespaceModal.tsx";
|
|
import { EditorWrapper } from "../components/editor/wrapper.tsx";
|
|
import { TagRouter } from "../components/editor/tags/editor.tsx";
|
|
|
|
export const Editor = () => {
|
|
const [packName, setPackName] = useState("");
|
|
const [loading, setLoading] = useState(true);
|
|
const [namespaces, setNamespaces] = useState<string[]>([]);
|
|
const [namespace, setNamespace] = useAtom(namespaceAtom);
|
|
|
|
const fetchNamespaces = async () => {
|
|
const res = await fetch("/api/pack/namespaces");
|
|
const json = await res.json();
|
|
setNamespaces(json);
|
|
};
|
|
|
|
useEffect(() => {
|
|
document.title = "BearMetal Packer";
|
|
fetch("/api/pack").then((res) => res.json()).then((json) => {
|
|
setPackName(json.packName);
|
|
setLoading(false);
|
|
});
|
|
fetchNamespaces();
|
|
}, []);
|
|
|
|
const setPackNameThing = async (event: SubmitEvent) => {
|
|
setLoading(true);
|
|
const res = await fetch("/api/pack", {
|
|
method: "POST",
|
|
body: new FormData(event.target as HTMLFormElement),
|
|
});
|
|
|
|
if (res.status === 200) {
|
|
document.title = packName;
|
|
setPackName(packName);
|
|
}
|
|
setLoading(false);
|
|
};
|
|
|
|
if (!packName) {
|
|
return (
|
|
<Modal>
|
|
{loading
|
|
? <p>Just a sec, trying to put the cats back in the bag.</p>
|
|
: (
|
|
<>
|
|
<form
|
|
method="POST"
|
|
onSubmit={setPackNameThing}
|
|
>
|
|
<label class="w-full">Set pack name</label>
|
|
<div class="flex gap-2">
|
|
<input type="text" name="packName" />
|
|
<button type="submit">Set</button>
|
|
</div>
|
|
</form>
|
|
<LabelledHr>OR</LabelledHr>
|
|
<PacksList setPackName={setPackName} />
|
|
</>
|
|
)}
|
|
</Modal>
|
|
);
|
|
}
|
|
|
|
const [showNamespaceModal, setShowNamespaceModal] = useState(false);
|
|
|
|
return (
|
|
<div class="flex h-full">
|
|
<div class="w-1/4 p-4 bg-mixed-400">
|
|
<div class="text-center">
|
|
<h1 class="text-2xl">BearMetalPacker</h1>
|
|
<PackInfo packName={packName} />
|
|
</div>
|
|
<LabelledHr>Namespaces</LabelledHr>
|
|
<div>
|
|
<ul class="w-full">
|
|
{namespaces.map((namespace) => (
|
|
<li
|
|
class="text-lg cursor-pointer even:bg-black/5"
|
|
onClick={() => setNamespace(namespace)}
|
|
>
|
|
{namespace}
|
|
</li>
|
|
))}
|
|
<li class="mt-4">
|
|
<button onClick={() => setShowNamespaceModal(true)}>
|
|
New Namespace
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
{showNamespaceModal && (
|
|
<NamespaceModal
|
|
close={() => {
|
|
setShowNamespaceModal(false);
|
|
fetchNamespaces();
|
|
}}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div class="p-4 w-max">
|
|
{!namespace ? <div>No namespace set</div> : (
|
|
<>
|
|
<h3 class="text-lg font-bold">
|
|
Namespace: <span class="italic">{namespace}</span>
|
|
</h3>
|
|
<Routes>
|
|
<Route index element={<Selector />} />
|
|
|
|
<Route
|
|
element={
|
|
<EditorWrapper>
|
|
<Outlet />
|
|
</EditorWrapper>
|
|
}
|
|
>
|
|
<Route
|
|
path="tags/*"
|
|
element={<TagRouter />}
|
|
/>
|
|
</Route>
|
|
</Routes>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|