File size: 4,160 Bytes
5fc68b0 136f9cf 5fc68b0 136f9cf 5fc68b0 136f9cf 5fc68b0 12621bc 136f9cf 5fc68b0 12621bc 5fc68b0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
// src/components/sidebar/app-sidebar.tsx
import {
Sidebar,
SidebarContent,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuItem,
SidebarMenuButton,
SidebarHeader,
} from "@/components/ui/sidebar";
import { routes } from "@/routes";
import { Link, useLocation, useNavigate } from "react-router-dom";
import { MessageSquare, Plus, Trash2 } from "lucide-react";
import { Button } from "../ui/button";
import { useLiveQuery } from "dexie-react-hooks";
import { ChatHistoryDB } from "@/lib/chat/memory";
import { useState } from "react";
import { toast } from "sonner";
import { IChatSession } from "@/lib/chat/types";
export function AppSidebar() {
const location = useLocation();
const navigate = useNavigate();
const chats = useLiveQuery(async () => {
const sessions = await ChatHistoryDB.getInstance().sessions.toArray();
return sessions.sort((a: IChatSession, b: IChatSession) => b.updatedAt - a.updatedAt);
});
const [hoveringId, setHoveringId] = useState<string | null>(null);
return (
<Sidebar>
<SidebarHeader className="flex flex-row items-center justify-between border-b">
<span className="text-lg font-bold">Sheer</span>
<Link to="/chat/new">
<Button variant="ghost" size="icon">
<Plus />
</Button>
</Link>
</SidebarHeader>
<SidebarContent className="gap-0">
<SidebarGroup>
<SidebarGroupLabel>Application</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{routes.map((route) => (
<SidebarMenuItem key={route.path}>
<SidebarMenuButton
asChild
isActive={location.pathname === route.path}
>
<Link to={route.path}>
{route.icon}
<span>{route.label}</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>Chats</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{chats?.map((chat: IChatSession) => (
<SidebarMenuItem key={chat.id}>
<SidebarMenuButton
asChild
isActive={location.pathname === `/chat/${chat.id}`}
className="flex flex-row items-center justify-between overflow-hidden"
onMouseEnter={() => setHoveringId(chat.id)}
onMouseLeave={() => setHoveringId(null)}
>
<Link to={`/chat/${chat.id}`} className="flex w-full items-center">
<div className="flex min-w-0 flex-1 items-center gap-2">
<MessageSquare className="h-4 w-4 shrink-0" />
<span className="truncate">{chat.name}</span>
</div>
<button
className={`ml-2 shrink-0 transition-transform duration-200 hover:text-destructive ${
hoveringId === chat.id || location.pathname === `/chat/${chat.id}`
? 'translate-x-0'
: 'translate-x-[200%]'
}`}
onClick={(e) => {
e.preventDefault();
ChatHistoryDB.getInstance().sessions.delete(chat.id);
toast.success("Chat deleted");
return navigate("/chat/new");
}}
>
<Trash2 className="h-4 w-4" />
</button>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
);
}
|