web / frontend /src /components /chat /ChatSidebar.tsx
Chandima Prabhath
feat: Add chat components and modals for enhanced user interaction
1904e4c
raw
history blame
6 kB
import React from "react";
import { format } from "date-fns";
import { Bot, TrashIcon, User, FileText, Settings, PanelLeft, Plus } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { Chat } from "@/types/chat";
import { ModeToggle } from "@/components/layout/ModeToggle";
interface ChatSidebarProps {
chats: Chat[];
activeChat: Chat | null;
isGeneratingTitle: boolean;
createNewChat: () => void;
selectChat: (id: string) => void;
onRequestDelete: (id: string) => void;
onOpenSettings: () => void;
onOpenSources: () => void;
openProfileModal: () => void;
isSidebarOpen: boolean;
setIsSidebarOpen: (open: boolean) => void;
}
export const ChatSidebar: React.FC<ChatSidebarProps> = ({
chats,
activeChat,
isGeneratingTitle,
createNewChat,
selectChat,
onRequestDelete,
onOpenSettings,
onOpenSources,
openProfileModal,
isSidebarOpen,
setIsSidebarOpen,
}) => {
return (
<div className={cn(
"fixed top-0 bottom-0 left-0 z-20 bg-background/90 backdrop-blur-lg",
"transition-transform duration-300 ease-in-out",
isSidebarOpen ? 'translate-x-0' : '-translate-x-full md:translate-x-0',
"w-72 lg:w-80 border-r border-border/50 flex-shrink-0",
"md:relative md:inset-auto h-full md:z-0"
)}>
<div className="flex flex-col h-full">
<div className="p-4 pb-0">
<div className="flex justify-between items-center">
<div className="flex items-center space-x-2">
<div className="h-8 w-8 bg-primary/90 rounded-md flex items-center justify-center">
<span className="text-white font-bold text-lg">AI</span>
</div>
<h1 className="text-xl font-semibold">
Insight AI
</h1>
</div>
<Button className="md:hidden" variant="ghost" size="icon" onClick={() => setIsSidebarOpen(false)}>
<PanelLeft className="h-5 w-5" />
</Button>
</div>
<div className="py-4">
<Button
onClick={createNewChat}
className="w-full justify-start gap-2"
variant="outline"
>
<Plus className="h-4 w-4" />
New Chat
</Button>
</div>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Bot className="h-5 w-5 text-primary" />
<span className="font-medium">Recent Chats</span>
</div>
</div>
</div>
<div className="flex-1 overflow-y-auto p-2 space-y-1 scrollbar-thin">
{chats.length === 0 ? (
<div className="text-center text-muted-foreground p-4">
No conversations yet. Start a new one!
</div>
) : (
chats.map(chat => (
<div
key={chat.id}
onClick={() => selectChat(chat.id)}
className={cn(
"flex items-center justify-between p-2 px-3 rounded-lg cursor-pointer group transition-all",
activeChat?.id === chat.id
? "bg-primary/10 border border-primary/20"
: "hover:bg-muted/50 border border-transparent"
)}
>
<div className="flex-1 truncate">
<div className={cn(
"font-medium truncate flex items-center",
activeChat?.id === chat.id && "text-primary"
)}>
<Bot className="h-3.5 w-3.5 mr-1.5 opacity-70" />
{chat.title}
{chat.id === activeChat?.id && isGeneratingTitle && (
<span className="ml-1.5 inline-block h-2 w-2 rounded-full bg-primary/70 animate-pulse"></span>
)}
</div>
<div className="text-xs text-muted-foreground">
{chat.messages.filter(m => m.sender === "user").length} messages • {format(new Date(chat.updatedAt), "MMM d")}
</div>
</div>
<Button
variant="ghost"
size="icon"
className="h-7 w-7 opacity-0 group-hover:opacity-100 transition-opacity hover:bg-destructive/10 hover:text-destructive"
onClick={(e) => {
e.stopPropagation();
onRequestDelete(chat.id);
}}
>
<TrashIcon className="h-3.5 w-3.5" />
</Button>
</div>
))
)}
</div>
{/* Sidebar Footer */}
<div className="p-3 space-y-2">
<Button
onClick={openProfileModal}
variant="ghost"
className="w-full justify-start gap-2 text-muted-foreground hover:text-foreground"
size="sm"
>
<User className="h-4 w-4" />
Profile
</Button>
<Button
onClick={onOpenSources}
variant="ghost"
className="w-full justify-start gap-2 text-muted-foreground hover:text-foreground"
size="sm"
>
<FileText className="h-4 w-4" />
View Sources
</Button>
<Button
onClick={onOpenSettings}
variant="ghost"
className="w-full justify-start gap-2 text-muted-foreground hover:text-foreground"
size="sm"
>
<Settings className="h-4 w-4" />
Settings
</Button>
<div className="flex items-center justify-between pt-2 border-t">
<span className="text-xs text-muted-foreground">Theme</span>
<ModeToggle />
</div>
</div>
</div>
</div>
);
};