add finishing touch in sidebar

This commit is contained in:
abhi1992002
2026-02-03 11:53:43 +05:30
parent e434b59003
commit 432bda5c70
4 changed files with 92 additions and 42 deletions

View File

@@ -35,10 +35,10 @@ export const ChatContainer = ({messages, status, error, input, setInput, handleM
setIsCreating(false);
}
}
return (
<div className="mx-auto h-[calc(100vh-60px)] w-full max-w-3xl pb-6">
<div className="mx-auto h-full w-full max-w-3xl pb-6">
<div className="flex h-full flex-col">
{sessionId ? (
<ChatMessagesContainer

View File

@@ -1,16 +1,32 @@
"use client";
import { Sidebar, SidebarHeader, SidebarContent, SidebarFooter, SidebarTrigger, useSidebar } from "@/components/ui/sidebar";
import { cn } from "@/lib/utils";
import { SparkleIcon, PlusIcon } from "@phosphor-icons/react";
import { SparkleIcon, PlusIcon, SpinnerGapIcon } from "@phosphor-icons/react";
import { motion } from "framer-motion";
import { Button } from "@/components/ui/button";
import { useState } from "react";
import { parseAsString, useQueryState } from "nuqs";
import { postV2CreateSession } from "@/app/api/__generated__/endpoints/chat/chat";
import { Button } from "@/components/atoms/Button/Button";
export function ChatSidebar() {
const { state } = useSidebar();
const isCollapsed = state === "collapsed";
const [isCreating, setIsCreating] = useState(false);
const [, setSessionId] = useQueryState("sessionId", parseAsString);
function handleNewChat() {
// TODO: Implement new chat creation
async function handleNewChat() {
if (isCreating) return;
setIsCreating(true);
try {
const response = await postV2CreateSession({
body: JSON.stringify({}),
});
if (response.status === 200 && response.data?.id) {
setSessionId(response.data.id);
}
} finally {
setIsCreating(false);
}
}
return (
@@ -19,23 +35,14 @@ export function ChatSidebar() {
collapsible="icon"
className="!top-[60px] !h-[calc(100vh-60px)]"
>
<SidebarHeader
{isCollapsed && <SidebarHeader
className={cn(
"flex md:pt-3.5",
"flex ",
isCollapsed
? "flex-row items-center justify-between gap-y-4 md:flex-col md:items-start md:justify-start"
: "flex-row items-center justify-between"
)}
>
<a href="#" className="flex items-center gap-2">
<SparkleIcon className="h-8 w-8" />
{!isCollapsed && (
<span className="font-semibold text-black dark:text-white">
Acme
</span>
)}
</a>
<motion.div
key={isCollapsed ? "header-collapsed" : "header-expanded"}
className={cn(
@@ -46,20 +53,38 @@ export function ChatSidebar() {
animate={{ opacity: 1 }}
transition={{ duration: 0.8 }}
>
<SidebarTrigger />
{isCollapsed && <div className="bg-secondary border border-neutral-400 h-fit p-1 rounded-3xl">
<SidebarTrigger />
</div>}
</motion.div>
</SidebarHeader>
</SidebarHeader>}
<SidebarContent className="gap-4 px-2 py-4">
<div className="flex items-center gap-2">
<Button
variant="primary"
size="icon"
onClick={handleNewChat}
disabled={isCreating}
className={cn(
"w-full justify-start gap-2",
isCollapsed && "justify-center px-2"
"w-full gap-2 rounded-3xl flex items-center justify-start h-fit px-4 py-2",
isCollapsed && "justify-center px-1 rounded-3xl "
)}
>
<PlusIcon className="h-4 w-4" />
{!isCollapsed && <span>New Chat</span>}
{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>
</SidebarContent>
<SidebarFooter className="px-2">
</SidebarFooter>

View File

@@ -5,18 +5,22 @@ import { DefaultChatTransport } from "ai";
import { useState, useMemo } from "react";
import { parseAsString, useQueryState } from "nuqs";
import { ChatSidebar } from "./components/ChatSidebar/ChatSidebar";
import { EmptySession } from "./components/EmptySession/EmptySession";
import { ChatMessagesContainer } from "./components/ChatMessagesContainer/ChatMessagesContainer";
import { postV2CreateSession } from "@/app/api/__generated__/endpoints/chat/chat";
import { ChatInput } from "@/components/contextual/Chat/components/ChatInput/ChatInput";
import { useSearchParams } from "next/navigation";
import { ChatContainer } from "./components/ChatContainer/ChatContainer";
import { SidebarProvider, SidebarInset } from "@/components/ui/sidebar";
import { Button } from "@/components/ui/button";
import { CopyIcon, CheckIcon } from "@phosphor-icons/react";
export default function Page() {
const [input, setInput] = useState("");
const searchParams = useSearchParams();
const sessionId = searchParams.get("sessionId") ?? undefined;
const [copied, setCopied] = useState(false);
const [sessionId] = useQueryState("sessionId", parseAsString);
function handleCopySessionId() {
if (!sessionId) return;
navigator.clipboard.writeText(sessionId);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
const transport = useMemo(() => {
if (!sessionId) return null;
@@ -56,18 +60,39 @@ export default function Page() {
}
return (
<SidebarProvider className="min-h-0 h-[calc(100vh-60px)]">
<SidebarProvider defaultOpen={false} className="min-h-0 h-[calc(100vh-72px)]">
<ChatSidebar />
<SidebarInset className="h-[calc(100vh-60px)]">
<ChatContainer
messages={messages}
status={status}
error={error}
input={input}
setInput={setInput}
handleMessageSubmit={handleMessageSubmit}
onSend={onSend}
/>
<SidebarInset className="flex h-[calc(100vh-80px)] flex-col relative">
{sessionId && (
<div className="flex items-center px-4 py-4 absolute">
<div className="flex items-center gap-2 rounded-3xl border border-neutral-400 bg-neutral-100 px-3 py-1.5 text-sm text-neutral-600 dark:bg-neutral-800 dark:text-neutral-400">
<span className=" text-xs">{sessionId.slice(0, 8)}...</span>
<Button
variant="ghost"
size="icon"
className="h-6 w-6"
onClick={handleCopySessionId}
>
{copied ? (
<CheckIcon className="h-3.5 w-3.5 text-green-500" />
) : (
<CopyIcon className="h-3.5 w-3.5" />
)}
</Button>
</div>
</div>
)}
<div className="flex-1 overflow-hidden">
<ChatContainer
messages={messages}
status={status}
error={error}
input={input}
setInput={setInput}
handleMessageSubmit={handleMessageSubmit}
onSend={onSend}
/>
</div>
</SidebarInset>
</SidebarProvider>
);

View File

@@ -62,7 +62,7 @@ export function Navbar() {
<PreviewBanner branchName={previewBranchName} />
) : null}
<nav
className="border-zinc-[#EFEFF0] inline-flex w-full items-center border border-[#EFEFF0] bg-[#F3F4F6]/20 p-3 backdrop-blur-[26px]"
className="border-none inline-flex w-full items-center border bg-[#FAFAFA] p-3 backdrop-blur-[26px]"
style={{ height: NAVBAR_HEIGHT_PX }}
>
{/* Left section */}