blob: cdd58c552959f6b90a099686b9b4827b430d9269 [file] [log] [blame]
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { v4 as uuidv4 } from "uuid";
import { useCallback, useState, useMemo } from "react";
import { Accordion, AccordionTrigger } from "./ui/accordion";
import { AccordionContent, AccordionItem } from "@radix-ui/react-accordion";
import { AppState, useCategories, useMode, useProjectId, useStateStore } from "@/lib/state";
import { CategoryItem } from "@/lib/categories";
import { Icon } from "./icon";
import { AppNode, NodeType } from "config";
function addResource(i: CategoryItem<NodeType>, store: AppState) {
const deselected = store.nodes.map((n) => ({
...n,
selected: false,
}));
store.setNodes(deselected);
store.addNode({
id: uuidv4(),
type: i.type,
data: i.init,
selected: true,
connectable: true,
} as any); // eslint-disable-line @typescript-eslint/no-explicit-any
}
export function Resources() {
const store = useStateStore();
const categories = useCategories();
const projectId = useProjectId();
const mode = useMode();
const onResourceAdd = useCallback(
(item: CategoryItem<NodeType>) => {
return () => addResource(item, store);
},
[store],
);
const [open, setOpen] = useState<string[]>(categories.map((c) => c.title));
const [searchValue, setSearchValue] = useState<string>("");
// Filter categories based on search value
const filteredCategories = useMemo(() => {
if (!searchValue.trim()) {
return categories;
}
const searchLower = searchValue.toLowerCase();
return categories
.map((category) => ({
...category,
items: category.items.filter((item) => item.title.toLowerCase().includes(searchLower)),
}))
.filter((category) => category.items.length > 0); // Remove empty categories
}, [categories, searchValue]);
return (
<>
<div className="px-3 pb-3 mt-2">
<Input
type="text"
placeholder="Search resources..."
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
className="w-full"
/>
</div>
<Accordion type="multiple" value={open} onValueChange={(v) => setOpen(v)}>
{filteredCategories.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: CategoryItem<NodeType>) => (
<Button
key={item.title}
onClick={onResourceAdd(item)}
style={{ justifyContent: "flex-start" }}
disabled={projectId == null || mode !== "edit"}
>
<Icon node={{ type: item.type, data: item.init } as AppNode} />
{item.title}
</Button>
))}
</div>
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</>
);
}