diff --git a/pkgs/clan-app/ui/src/routes/Clan/Clan.css b/pkgs/clan-app/ui/src/routes/Clan/Clan.css index 977797521..d74a2c313 100644 --- a/pkgs/clan-app/ui/src/routes/Clan/Clan.css +++ b/pkgs/clan-app/ui/src/routes/Clan/Clan.css @@ -2,3 +2,12 @@ opacity: 0; transition: opacity 0.5s ease; } + +.create-backdrop { + @apply absolute top-0 left-0 w-full h-svh flex justify-center items-center backdrop-blur-0 z-50; + -webkit-backdrop-filter: blur(4px); +} + +.create-modal { + @apply min-w-96; +} diff --git a/pkgs/clan-app/ui/src/routes/Clan/Clan.tsx b/pkgs/clan-app/ui/src/routes/Clan/Clan.tsx index d9383dcff..cd47110a4 100644 --- a/pkgs/clan-app/ui/src/routes/Clan/Clan.tsx +++ b/pkgs/clan-app/ui/src/routes/Clan/Clan.tsx @@ -1,5 +1,5 @@ import { RouteSectionProps } from "@solidjs/router"; -import { Component, JSX } from "solid-js"; +import { Component, JSX, Show, createSignal } from "solid-js"; import { useClanURI } from "@/src/hooks/clan"; import { CubeScene } from "@/src/scene/cubes"; import { MachinesQueryResult, useMachinesQuery } from "@/src/queries/queries"; @@ -10,6 +10,9 @@ import { Button } from "@/src/components/Button/Button"; import { Splash } from "@/src/scene/splash"; import cx from "classnames"; import "./Clan.css"; +import { Modal } from "@/src/components/Modal/Modal"; +import { TextInput } from "@/src/components/Form/TextInput"; +import { createForm, FieldValues, reset } from "@modular-forms/solid"; export const Clan: Component = (props) => { return ( @@ -27,17 +30,88 @@ export const Clan: Component = (props) => { ); }; +interface CreateFormValues extends FieldValues { + name: string; +} +interface MockProps { + onClose: () => void; + onSubmit: (formValues: CreateFormValues) => void; +} +const MockCreateMachine = (props: MockProps) => { + let container: Node; + + const [form, { Form, Field, FieldArray }] = createForm(); + + return ( +
(container = el)} class="create-backdrop"> + { + reset(form); + props.onClose(); + }} + class="create-modal" + title="Create Machine" + > + {() => ( +
+ + {(field, props) => ( + <> + + + )} + + +
+ + +
+
+ )} +
+
+ ); +}; + const ClanSceneController = () => { const clanURI = useClanURI({ force: true }); - const onCreate = async (id: string) => { + const [dialogHandlers, setDialogHandlers] = createSignal<{ + resolve: ({ id }: { id: string }) => void; + reject: (err: unknown) => void; + } | null>(null); + + const onCreate = async (): Promise<{ id: string }> => { + return new Promise((resolve, reject) => { + setShowModal(true); + setDialogHandlers({ resolve, reject }); + }); + }; + + const sendCreate = async (values: CreateFormValues) => { const api = callApi("create_machine", { opts: { clan_dir: { identifier: clanURI, }, machine: { - name: id, + name: values.name, }, }, }); @@ -49,14 +123,34 @@ const ClanSceneController = () => { // Important: rejects the promise throw new Error(res.errors[0].message); } - return; + return { id: values.name }; }; + const [showModal, setShowModal] = createSignal(false); + return ( {({ query }) => { return ( <> + + { + setShowModal(false); + dialogHandlers()?.reject(new Error("User cancelled")); + }} + onSubmit={async (values) => { + try { + const result = await sendCreate(values); + dialogHandlers()?.resolve(result); + setShowModal(false); + } catch (err) { + dialogHandlers()?.reject(err); + setShowModal(false); + } + }} + /> +
{ produce((s) => { for (const machineId in s.sceneData[clanURI]) { // Reset the position of each machine to [0, 0] + s.sceneData[clanURI] = {}; // Clear the entire object // delete s.sceneData[clanURI][machineId]; } }), @@ -90,6 +185,7 @@ const ClanSceneController = () => {
+