Nav Menu Upgrades and Minor UX Improvements (#869)

* Converted navigation menu into a dropdown menu
* Moved collapsed side panel menu icons into top row
* Auto refresh when conversation is deleted to update side panel and route back to main page if deletion is on current conversation
* Highlight the current conversation in the side panel
* Dynamic homepage messages with current day and time of day.
* `colorutils` upgraded to have more expansive tailwind color options and dynamic class name generation.
* Converted create agent button alert into shadcn `ToolTip`
* Colored lines and icons for agents in chat window
* Cleaned up border styling in dark mode
* fixed three dot menu in side panel to be more easier to click
* Add the KhojLogo import in the nav menu and use a default user profile icon when not authenticated
* Get rid of custom --box-shadow CSS variable
* Pass the agent metadat through the chat body data in order to style the send button
* Add login to the unauthenticated login view, redirecto to home if conversation history not loaded
* Set a max height for the input text area
* Simplify tailwind class names

---------

Co-authored-by: sabaimran <narmiabas@gmail.com>
This commit is contained in:
Raghav Tirumale
2024-07-27 04:42:00 -04:00
committed by GitHub
parent 8503d7a07b
commit 1685c60e3c
33 changed files with 1790 additions and 7771 deletions

View File

@@ -8,6 +8,7 @@ import { UserProfile, useAuthenticatedData } from "@/app/common/auth";
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
import Link from "next/link";
import useSWR from "swr";
import Image from "next/image";
import {
Command,
@@ -77,6 +78,7 @@ import { Label } from "@/components/ui/label";
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog";
import { modifyFileFilterForConversation } from "@/app/common/chatFunctions";
import { ScrollAreaScrollbar } from "@radix-ui/react-scroll-area";
import { KhojLogo } from "../logo/khogLogo";
// Define a fetcher function
const fetcher = (url: string) => fetch(url).then((res) => res.json());
@@ -364,9 +366,7 @@ function SessionsAndFiles(props: SessionsAndFilesProps) {
}
</div>
<FilesMenu conversationId={props.conversationId} uploadedFiles={props.uploadedFiles} isMobileWidth={props.isMobileWidth} />
{props.userProfile &&
<UserProfileComponent userProfile={props.userProfile} webSocketConnected={props.webSocketConnected} collapsed={false} />
}</>
</>
)
}
@@ -487,6 +487,15 @@ function ChatSessionActionMenu(props: ChatSessionActionMenuProps) {
onClick={() => {
deleteConversation(props.conversationId);
setIsDeleting(false);
var currConversationId = parseInt(new URLSearchParams(window.location.search).get('conversationId') || "0");
//edge case for deleting current conversation
if (currConversationId === parseInt(props.conversationId)) {
window.location.href = '/';
}
//reload side panel
setTimeout(() => {
window.location.reload();
}, 1000);
}}
className="bg-rose-500 hover:bg-rose-600">Delete</AlertDialogAction>
</AlertDialogFooter>
@@ -523,13 +532,13 @@ function ChatSessionActionMenu(props: ChatSessionActionMenuProps) {
function ChatSession(props: ChatHistory) {
const [isHovered, setIsHovered] = useState(false);
var currConversationId = parseInt(new URLSearchParams(window.location.search).get('conversationId') || "-1");
return (
<div
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
key={props.conversation_id}
className={`${styles.session} ${props.compressed ? styles.compressed : '!max-w-full'} ${isHovered ? `${styles.sessionHover}` : ''}`}>
className={`${styles.session} ${props.compressed ? styles.compressed : '!max-w-full'} ${isHovered ? `${styles.sessionHover}` : ''} ${currConversationId === parseInt(props.conversation_id) && currConversationId != -1 ? "dark:bg-neutral-800 bg-white" : ""}`}>
<Link href={`/chat?conversationId=${props.conversation_id}`} onClick={() => props.showSidePanel(false)}>
<p className={styles.session}>{props.slug || "New Conversation 🌱"}</p>
</Link>
@@ -588,45 +597,6 @@ interface UserProfileProps {
collapsed: boolean;
}
function UserProfileComponent(props: UserProfileProps) {
if (props.collapsed) {
return (
<div className={styles.profile}>
<Avatar className="h-7 w-7">
<AvatarImage src={props.userProfile.photo} alt="user profile" />
<AvatarFallback>
{props.userProfile.username[0]}
</AvatarFallback>
</Avatar>
</div>
);
}
return (
<div className={styles.profile}>
<Link href="/settings">
<Avatar>
<AvatarImage src={props.userProfile.photo} alt="user profile" />
<AvatarFallback>
{props.userProfile.username[0]}
</AvatarFallback>
</Avatar>
</Link>
<div className={styles.profileDetails}>
<p>{props.userProfile?.username}</p>
{/* Connected Indicator */}
<div className="flex gap-2 items-center">
<div className={`inline-flex h-4 w-4 rounded-full opacity-75 ${props.webSocketConnected ? 'bg-green-500' : 'bg-rose-500'}`}></div>
<p className="text-muted-foreground text-sm">
{props.webSocketConnected ? "Connected" : "Disconnected"}
</p>
</div>
</div>
</div>
);
}
const fetchChatHistory = async (url: string) => {
const response = await fetch(url, {
method: 'GET',
@@ -700,19 +670,11 @@ export default function SidePanel(props: SidePanelProps) {
}
}, [chatSessions]);
function newConvo() {
window.location.href = '/';
}
return (
<div className={`${styles.panel} ${enabled ? styles.expanded : styles.collapsed}`}>
<div className={`flex items-center justify-between ${(enabled || props.isMobileWidth) ? 'flex-row' : 'flex-col'}`}>
<div className={`${styles.panel} ${enabled ? styles.expanded : styles.collapsed} mt-1`}>
<div className={`flex justify-between flex-row`}>
<Link href='/'>
<img
src="/khoj-logo.svg"
alt="khoj logo"
width={52}
height={52} />
<KhojLogo />
</Link>
{
authenticatedData && props.isMobileWidth ?
@@ -748,8 +710,8 @@ export default function SidePanel(props: SidePanelProps) {
</DrawerContent>
</Drawer>
:
<div className={`flex items-center ${enabled ? 'flex-row gap-2' : 'flex-col pt-2'}`}>
<Link className={` ${enabled ? 'ml-2' : ''}`} href="/">
<div className={`${enabled ? 'flex items-center flex-row gap-2' : 'flex'}`}>
<Link className={`ml-4 mr-4`} href="/">
{enabled ? <NotePencil className="h-6 w-6" /> : <NotePencil className="h-6 w-6" color="gray" />}
</Link>
<button className={styles.button} onClick={() => setEnabled(!enabled)}>

View File

@@ -7,7 +7,7 @@ div.session {
font-size: medium;
display: grid;
grid-template-columns: minmax(auto, 400px) 1fr;
gap: 1rem;
gap: 0rem;
}
div.compressed {