Files
nextjs-chat-gpt/components/chat/ChatSidebar.tsx
T

108 lines
3.1 KiB
TypeScript

'use client';
import { RiAddLine, RiMoreLine, RiDeleteBinLine } from '@remixicon/react';
import {
Sidebar,
SidebarContent,
SidebarHeader,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuItem,
SidebarMenuButton,
SidebarMenuAction,
useSidebar,
} from '@/components/ui/sidebar';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Button } from '@/components/ui/button';
import { ChatSearch } from './ChatSearch';
import type { StoredChat } from '@/services/indexed-db/chat-store';
export type Chat = StoredChat;
interface ChatSidebarProps {
chats: Chat[];
activeChatId: string | null;
onSelectChat: (chatId: string) => void;
onNewChat: () => void;
onDeleteChat: (chatId: string) => void;
}
export function ChatSidebar({
chats,
activeChatId,
onSelectChat,
onNewChat,
onDeleteChat,
}: ChatSidebarProps) {
const { setOpenMobile } = useSidebar();
const selectChat = (chatId: string) => {
onSelectChat(chatId);
setOpenMobile(false);
};
return (
<Sidebar>
<SidebarHeader>
<div className="flex h-7 items-center justify-between gap-2 pl-2">
<span className="text-xl font-semibold tracking-tight">ChatGPT</span>
<ChatSearch chats={chats} activeChatId={activeChatId} onSelectChat={selectChat} />
</div>
<Button
onClick={() => {
onNewChat();
setOpenMobile(false);
}}
variant="outline"
className="mt-2 w-full justify-start gap-2"
>
<RiAddLine className="size-4" />
New Chat
</Button>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Recent Chats</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{chats.map((chat) => (
<SidebarMenuItem key={chat.id}>
<SidebarMenuButton
isActive={chat.id === activeChatId}
onClick={() => selectChat(chat.id)}
tooltip={chat.title}
>
<span>{chat.title}</span>
</SidebarMenuButton>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuAction showOnHover aria-label={`Options for ${chat.title}`}>
<RiMoreLine className="size-4" />
</SidebarMenuAction>
</DropdownMenuTrigger>
<DropdownMenuContent side="right" align="start">
<DropdownMenuItem
onClick={() => onDeleteChat(chat.id)}
>
<RiDeleteBinLine className="size-4" />
Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
);
}