refactor: enhance ToolsDropdownList with Popover and Command components for improved usability

This commit is contained in:
ecwu
2025-01-06 00:29:21 +08:00
parent 22e3760b7f
commit a7bbe1e000

View File

@@ -16,6 +16,22 @@ import {
NavigationMenu,
NavigationMenuList,
} from "@/components/ui/navigation-menu";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { BrushIcon } from "lucide-react";
import { useToast } from "@/hooks/use-toast";
interface APITemplateDropdownProps {
label: string;
@@ -133,85 +149,71 @@ function APIsDropdownList({
function ToolsDropdownList() {
const ctx = useContext(AppContext);
if (!ctx) return <div>error</div>;
const { toast } = useToast();
const [open, setOpen] = React.useState(false);
const { chatStore, setChatStore } = ctx;
return (
<NavigationMenuItem>
<NavigationMenuTrigger>
<span>{Tr(`Tools`)}</span>
</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px]">
{ctx.templateTools.map((t, index) => (
<li key={index}>
<NavigationMenuLink asChild>
<a
onClick={() => {
chatStore.toolsString = t.toolsString;
setChatStore({ ...chatStore });
}}
className={cn(
"block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
chatStore.toolsString === t.toolsString
? "bg-accent text-accent-foreground"
: ""
)}
>
<div className="text-sm font-medium leading-none">
<div className="flex items-center space-x-4 mx-3">
<p className="text-sm text-muted-foreground">{Tr(`Tools`)}</p>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button variant="outline" className="w-[150px] justify-start">
{chatStore.toolsString ? (
<>
{
ctx.templateTools.find(
(t) => t.toolsString === chatStore.toolsString
)?.name
}
</>
) : (
<>+ {Tr(`Set tools`)}</>
)}
</Button>
</PopoverTrigger>
<PopoverContent className="p-0" side="right" align="start">
<Command>
<CommandInput placeholder="You can search..." />
<CommandList>
<CommandEmpty>{Tr(`No results found.`)}</CommandEmpty>
<CommandGroup>
{chatStore.toolsString && (
<CommandItem
key={-1}
value=""
onSelect={() => {
chatStore.toolsString = "";
setChatStore({ ...chatStore });
toast({
title: "Tools Cleaned",
description: "Tools cleaned successfully",
});
setOpen(false);
}}
>
<BrushIcon /> {Tr(`Clear tools`)}
</CommandItem>
)}
{ctx.templateTools.map((t, index) => (
<CommandItem
key={index}
value={t.toolsString}
onSelect={(value) => {
chatStore.toolsString = value;
setChatStore({ ...chatStore });
}}
>
{t.name}
</div>
<p className="line-clamp-2 text-sm leading-snug text-muted-foreground">
{t.toolsString}
</p>
</a>
</NavigationMenuLink>
<div className="mt-2 flex justify-between">
<Button
variant="ghost"
size="sm"
onClick={() => {
chatStore.toolsString = "";
setChatStore({ ...chatStore });
}}
>
{Tr(`Clear`)}
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => {
const name = prompt(`Give **tools** template a name`);
if (!name) return;
t.name = name;
ctx.setTemplateTools(structuredClone(ctx.templateTools));
}}
>
Edit
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => {
if (
!confirm(
`Are you sure to delete this **tools** template?`
)
) {
return;
}
ctx.templateTools.splice(index, 1);
ctx.setTemplateTools(structuredClone(ctx.templateTools));
}}
>
Delete
</Button>
</div>
</li>
))}
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
</div>
);
}
@@ -219,7 +221,8 @@ const APIListMenu: React.FC = () => {
const ctx = useContext(AppContext);
if (!ctx) return <div>error</div>;
return (
<div className="flex flex-col p-2 gap-2 w-full">
<div className="flex flex-col m-2 gap-2 w-full">
{ctx.templateTools.length > 0 && <ToolsDropdownList />}
<NavigationMenu>
<NavigationMenuList>
{ctx.templateAPIs.length > 0 && (
@@ -260,13 +263,6 @@ const APIListMenu: React.FC = () => {
)}
</NavigationMenuList>
</NavigationMenu>
{ctx.templateTools.length > 0 && (
<NavigationMenu>
<NavigationMenuList>
<ToolsDropdownList />
</NavigationMenuList>
</NavigationMenu>
)}
</div>
);
};