mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-03 03:14:57 -05:00
another ui/ux polishing in chat sidebar
This commit is contained in:
@@ -1,18 +1,26 @@
|
||||
"use client";
|
||||
import { Sidebar, SidebarHeader, SidebarContent, SidebarFooter, SidebarTrigger, useSidebar } from "@/components/ui/sidebar";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { SparkleIcon, PlusIcon, SpinnerGapIcon } from "@phosphor-icons/react";
|
||||
import { SparkleIcon, PlusIcon, SpinnerGapIcon, ChatCircleIcon } from "@phosphor-icons/react";
|
||||
import { motion } from "framer-motion";
|
||||
import { useState } from "react";
|
||||
import { parseAsString, useQueryState } from "nuqs";
|
||||
import { postV2CreateSession } from "@/app/api/__generated__/endpoints/chat/chat";
|
||||
import { postV2CreateSession, useGetV2ListSessions, getGetV2ListSessionsQueryKey } from "@/app/api/__generated__/endpoints/chat/chat";
|
||||
import { Button } from "@/components/atoms/Button/Button";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
export function ChatSidebar() {
|
||||
const { state } = useSidebar();
|
||||
const isCollapsed = state === "collapsed";
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
const [, setSessionId] = useQueryState("sessionId", parseAsString);
|
||||
const [sessionId, setSessionId] = useQueryState("sessionId", parseAsString);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { data: sessionsResponse, isLoading: isLoadingSessions } = useGetV2ListSessions(
|
||||
{ limit: 50 },
|
||||
);
|
||||
|
||||
const sessions = sessionsResponse?.status === 200 ? sessionsResponse.data.sessions : [];
|
||||
|
||||
async function handleNewChat() {
|
||||
if (isCreating) return;
|
||||
@@ -23,12 +31,29 @@ export function ChatSidebar() {
|
||||
});
|
||||
if (response.status === 200 && response.data?.id) {
|
||||
setSessionId(response.data.id);
|
||||
queryClient.invalidateQueries({ queryKey: getGetV2ListSessionsQueryKey() });
|
||||
}
|
||||
} finally {
|
||||
setIsCreating(false);
|
||||
}
|
||||
}
|
||||
|
||||
function handleSelectSession(id: string) {
|
||||
setSessionId(id);
|
||||
}
|
||||
|
||||
function formatDate(dateString: string) {
|
||||
const date = new Date(dateString);
|
||||
const now = new Date();
|
||||
const diffMs = now.getTime() - date.getTime();
|
||||
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
||||
|
||||
if (diffDays === 0) return "Today";
|
||||
if (diffDays === 1) return "Yesterday";
|
||||
if (diffDays < 7) return `${diffDays} days ago`;
|
||||
return date.toLocaleDateString();
|
||||
}
|
||||
|
||||
return (
|
||||
<Sidebar
|
||||
variant="inset"
|
||||
@@ -59,32 +84,64 @@ export function ChatSidebar() {
|
||||
</div>}
|
||||
</motion.div>
|
||||
</SidebarHeader>}
|
||||
<SidebarContent className="gap-4 px-2 py-4">
|
||||
<SidebarContent className="gap-4 px-2 py-4 overflow-y-auto [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="icon"
|
||||
onClick={handleNewChat}
|
||||
disabled={isCreating}
|
||||
className={cn(
|
||||
"w-full gap-2 rounded-3xl flex items-center justify-start h-fit px-4 py-2",
|
||||
isCollapsed && "justify-center px-1 rounded-3xl "
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={handleNewChat}
|
||||
disabled={isCreating}
|
||||
className={cn(
|
||||
"w-full gap-2 rounded-3xl flex items-center justify-center h-fit px-3 py-2 bg-purple-100 border-purple-400 text-purple-600 hover:bg-purple-200 hover:border-purple-500 hover:text-purple-700",
|
||||
isCollapsed && "justify-center px-1 rounded-3xl"
|
||||
)}
|
||||
>
|
||||
{isCreating ? (
|
||||
<SpinnerGapIcon className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<PlusIcon className="h-4 w-4" weight="bold" />
|
||||
)}
|
||||
{!isCollapsed && <span>{isCreating ? "Creating..." : "New Chat"}</span>}
|
||||
</Button>
|
||||
{!isCollapsed && (
|
||||
<div className="bg-secondary border border-neutral-400 h-fit p-1 rounded-3xl">
|
||||
<SidebarTrigger />
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
{isCreating ? (
|
||||
<SpinnerGapIcon className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
)}
|
||||
{!isCollapsed && <span>{isCreating ? "Creating..." : "New Chat"}</span>}
|
||||
</Button>
|
||||
{!isCollapsed && <div className="bg-secondary border border-neutral-400 h-fit p-1 rounded-3xl">
|
||||
<SidebarTrigger />
|
||||
|
||||
</div>}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{!isCollapsed && (
|
||||
<div className="flex flex-col gap-1 mt-4">
|
||||
{isLoadingSessions ? (
|
||||
<div className="flex items-center justify-center py-4">
|
||||
<SpinnerGapIcon className="h-5 w-5 animate-spin text-neutral-400" />
|
||||
</div>
|
||||
) : sessions.length === 0 ? (
|
||||
<p className="text-sm text-neutral-500 text-center py-4">No conversations yet</p>
|
||||
) : (
|
||||
sessions.map((session) => (
|
||||
<button
|
||||
key={session.id}
|
||||
onClick={() => handleSelectSession(session.id)}
|
||||
className={cn(
|
||||
"flex items-center gap-3 rounded-lg px-3 py-2 text-left text-sm transition-colors hover:bg-neutral-100 dark:hover:bg-neutral-800",
|
||||
sessionId === session.id && "bg-neutral-100 dark:bg-neutral-800"
|
||||
)}
|
||||
>
|
||||
<ChatCircleIcon className="h-4 w-4 shrink-0 text-neutral-500" />
|
||||
<div className="flex flex-col overflow-hidden">
|
||||
<span className="truncate font-medium">
|
||||
{session.title || `Untitled chat`}
|
||||
</span>
|
||||
<span className="text-xs text-neutral-500">
|
||||
{formatDate(session.updated_at)}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</SidebarContent>
|
||||
<SidebarFooter className="px-2">
|
||||
</SidebarFooter>
|
||||
|
||||
@@ -27,8 +27,8 @@ import {
|
||||
|
||||
const SIDEBAR_COOKIE_NAME = "sidebar_state"
|
||||
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
|
||||
const SIDEBAR_WIDTH = "16rem"
|
||||
const SIDEBAR_WIDTH_MOBILE = "18rem"
|
||||
const SIDEBAR_WIDTH = "20rem"
|
||||
const SIDEBAR_WIDTH_MOBILE = "20rem"
|
||||
const SIDEBAR_WIDTH_ICON = "3rem"
|
||||
const SIDEBAR_KEYBOARD_SHORTCUT = "b"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user