Template
77 lines
2.5 KiB
TypeScript
77 lines
2.5 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { RiCheckLine, RiSearchLine } from '@remixicon/react';
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
Command,
|
|
CommandEmpty,
|
|
CommandGroup,
|
|
CommandInput,
|
|
CommandItem,
|
|
CommandList,
|
|
} from '@/components/ui/command';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
} from '@/components/ui/dialog';
|
|
import type { StoredChat } from '@/services/indexed-db/chat-store';
|
|
|
|
interface ChatSearchProps {
|
|
chats: StoredChat[];
|
|
activeChatId: string | null;
|
|
onSelectChat: (chatId: string) => void;
|
|
}
|
|
|
|
export function ChatSearch({ chats, activeChatId, onSelectChat }: ChatSearchProps) {
|
|
const [open, setOpen] = useState(false);
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
<DialogTrigger asChild>
|
|
<Button type="button" variant="ghost" size="icon" className="size-7" aria-label="Search chats">
|
|
<RiSearchLine className="size-5" aria-hidden="true" />
|
|
</Button>
|
|
</DialogTrigger>
|
|
<DialogContent className="max-w-[calc(100%-2rem)] overflow-hidden p-0 sm:max-w-lg [&>button]:top-2.5">
|
|
<DialogTitle className="sr-only">Search chats</DialogTitle>
|
|
<DialogDescription className="sr-only">
|
|
Search your saved chats by title and select one to continue the conversation.
|
|
</DialogDescription>
|
|
<Command>
|
|
<CommandInput placeholder="Search chats..." aria-label="Search chats" className="pr-10" />
|
|
<CommandList className="max-h-[min(24rem,60dvh)]">
|
|
<CommandEmpty>
|
|
{chats.length === 0 ? 'No chats yet. Start a new chat to get started.' : 'No chats found.'}
|
|
</CommandEmpty>
|
|
<CommandGroup heading="Recent chats">
|
|
{chats.map((chat) => (
|
|
<CommandItem
|
|
key={chat.id}
|
|
value={chat.id}
|
|
keywords={[chat.title]}
|
|
onSelect={() => {
|
|
setOpen(false);
|
|
onSelectChat(chat.id);
|
|
}}
|
|
>
|
|
<span className="min-w-0 flex-1 truncate">{chat.title}</span>
|
|
{chat.id === activeChatId && (
|
|
<>
|
|
<RiCheckLine className="size-4" aria-hidden="true" />
|
|
<span className="sr-only">Current chat</span>
|
|
</>
|
|
)}
|
|
</CommandItem>
|
|
))}
|
|
</CommandGroup>
|
|
</CommandList>
|
|
</Command>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|