Canvas: build application infrastructure with drag and drop
Change-Id: I5cfd12e67794f3376c5c025af29470d52d77cf16
diff --git a/apps/canvas/src/components/resources.tsx b/apps/canvas/src/components/resources.tsx
new file mode 100644
index 0000000..7471c1f
--- /dev/null
+++ b/apps/canvas/src/components/resources.tsx
@@ -0,0 +1,51 @@
+import { Button } from "@/components/ui/button";
+import { ReactFlowInstance, useReactFlow } from "@xyflow/react";
+import { v4 as uuidv4 } from "uuid";
+import { useCallback, useState } from "react";
+import { Accordion, AccordionTrigger } from "./ui/accordion";
+import { AccordionContent, AccordionItem } from "@radix-ui/react-accordion";
+import { useCategories } from "@/lib/state";
+import { CategoryItem } from "@/lib/categories";
+import { Icon } from "./icon";
+
+function addResource(i: CategoryItem, flow: ReactFlowInstance) {
+ flow.addNodes({
+ id: uuidv4(),
+ position: {
+ x: 0,
+ y: 0,
+ },
+ type: i.type,
+ connectable: true,
+ data: i.init,
+ });
+}
+
+export function Resources() {
+ let flow = useReactFlow();
+ const categories = useCategories();
+ let onResourceAdd = useCallback((item: CategoryItem) => {
+ return () => addResource(item, flow);
+ }, [flow]);
+ const [open, setOpen] = useState<string[]>(categories.map((c) => c.title));
+ return (
+ <>
+ <Accordion type="multiple" value={open} onValueChange={(v) => setOpen(v)}>
+ {categories.map((c) => (
+ <AccordionItem key={c.title} value={c.title} className={"px-3" + (c.active ? " bg-amber-100" : "")}>
+ <AccordionTrigger>
+ {c.title}
+ </AccordionTrigger>
+ <AccordionContent>
+ <div className="flex flex-col space-y-1">
+ {c.items.map((item) => (
+ <Button key={item.title} onClick={onResourceAdd(item)} style={{ justifyContent: "flex-start" }}>{Icon(item.type)}{item.title}</Button>
+ ))}
+ </div>
+ </AccordionContent>
+ </AccordionItem>
+ ))}
+ </Accordion>
+ </>
+ );
+}