From 9b554feb919628087f2fa26bc319ad66683bf663 Mon Sep 17 00:00:00 2001 From: Debanjum Singh Solanky Date: Sun, 20 Oct 2024 20:34:12 -0700 Subject: [PATCH] Show agent details card on hover on agent pill on web app home page - Double click on agent to open edit agent card - Focus on chat input pane when agent selected/clicked for quick, smooth agent switch and message flow - Hover on agent to see agent detail card on non-mobile displays - Use debounce to only show when hover on card for a bit --- src/interface/web/app/common/utils.ts | 16 ++++ src/interface/web/app/page.tsx | 115 +++++++++++++++++++++----- 2 files changed, 110 insertions(+), 21 deletions(-) diff --git a/src/interface/web/app/common/utils.ts b/src/interface/web/app/common/utils.ts index 1e7337b8..6c10ba8a 100644 --- a/src/interface/web/app/common/utils.ts +++ b/src/interface/web/app/common/utils.ts @@ -70,3 +70,19 @@ export function useIsMobileWidth() { return isMobileWidth; } + +export function useDebounce(value: T, delay: number): T { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const handler = setTimeout(() => { + setDebouncedValue(value); + }, delay); + + return () => { + clearTimeout(handler); + }; + }, [value, delay]); + + return debouncedValue; +} diff --git a/src/interface/web/app/page.tsx b/src/interface/web/app/page.tsx index 83081e2f..07dbd529 100644 --- a/src/interface/web/app/page.tsx +++ b/src/interface/web/app/page.tsx @@ -3,9 +3,8 @@ import "./globals.css"; import styles from "./page.module.css"; import "katex/dist/katex.min.css"; -import React, { useEffect, useState } from "react"; +import React, { useEffect, useRef, useState } from "react"; import useSWR from "swr"; -import Image from "next/image"; import { ArrowCounterClockwise } from "@phosphor-icons/react"; import { Card, CardTitle } from "@/components/ui/card"; @@ -16,14 +15,21 @@ import { ChatInputArea, ChatOptions } from "@/app/components/chatInputArea/chatI import { Suggestion, suggestionsData } from "@/app/components/suggestions/suggestionsData"; import LoginPrompt from "@/app/components/loginPrompt/loginPrompt"; -import { useAuthenticatedData, UserConfig, useUserConfig } from "@/app/common/auth"; +import { + isUserSubscribed, + useAuthenticatedData, + UserConfig, + useUserConfig, +} from "@/app/common/auth"; import { convertColorToBorderClass } from "@/app/common/colorUtils"; import { getIconFromIconName } from "@/app/common/iconUtils"; import { AgentData } from "@/app/agents/page"; import { createNewConversation } from "./common/chatFunctions"; -import { useIsMobileWidth } from "./common/utils"; -import { useSearchParams } from "next/navigation"; +import { useDebounce, useIsMobileWidth } from "./common/utils"; +import { useRouter, useSearchParams } from "next/navigation"; import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; +import { AgentCard } from "@/app/components/agentCard/agentCard"; +import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; interface ChatBodyDataProps { chatOptionsData: ChatOptions | null; @@ -49,10 +55,15 @@ function ChatBodyData(props: ChatBodyDataProps) { const [processingMessage, setProcessingMessage] = useState(false); const [greeting, setGreeting] = useState(""); const [shuffledOptions, setShuffledOptions] = useState([]); + const [hoveredAgent, setHoveredAgent] = useState(null); + const debouncedHoveredAgent = useDebounce(hoveredAgent, 500); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [selectedAgent, setSelectedAgent] = useState("khoj"); const [agentIcons, setAgentIcons] = useState([]); const [agents, setAgents] = useState([]); + const chatInputRef = useRef(null); const [showLoginPrompt, setShowLoginPrompt] = useState(false); + const router = useRouter(); const searchParams = useSearchParams(); const queryParam = searchParams.get("q"); @@ -62,6 +73,12 @@ function ChatBodyData(props: ChatBodyDataProps) { } }, [queryParam]); + useEffect(() => { + if (debouncedHoveredAgent) { + setIsPopoverOpen(true); + } + }, [debouncedHoveredAgent]); + const onConversationIdChange = props.onConversationIdChange; const agentsFetcher = () => @@ -73,6 +90,10 @@ function ChatBodyData(props: ChatBodyDataProps) { revalidateOnFocus: false, }); + const openAgentEditCard = (agentSlug: string) => { + router.push(`/agents?agent=${agentSlug}`); + }; + function shuffleAndSetOptions() { const shuffled = FisherYatesShuffle(suggestionsData); setShuffledOptions(shuffled.slice(0, 3)); @@ -188,23 +209,67 @@ function ChatBodyData(props: ChatBodyDataProps) { {!props.isMobileWidth && (
- {agentIcons.map((icon, index) => ( - ( + { + if (!open) { + setHoveredAgent(null); + setIsPopoverOpen(false); + } + }} > - setSelectedAgent(agents[index].slug)} + + openAgentEditCard(agent.slug)} + onClick={() => { + setSelectedAgent(agent.slug); + chatInputRef.current?.focus(); + setHoveredAgent(null); + setIsPopoverOpen(false); + }} + onMouseEnter={() => setHoveredAgent(agent.slug)} + onMouseLeave={() => { + setHoveredAgent(null); + setIsPopoverOpen(false); + }} + > + + {agentIcons[index]} {agent.name} + + + + { + setHoveredAgent(null); + setIsPopoverOpen(false); + }} > - {icon} {agents[index].name} - - + {}} + modelOptions={[]} + inputToolOptions={{}} + outputModeOptions={{}} + /> + + ))}
@@ -225,6 +290,7 @@ function ChatBodyData(props: ChatBodyDataProps) { conversationId={null} isMobileWidth={props.isMobileWidth} setUploadedFiles={props.setUploadedFiles} + ref={chatInputRef} /> )} @@ -281,7 +347,13 @@ function ChatBodyData(props: ChatBodyDataProps) { > setSelectedAgent(agents[index].slug)} + onDoubleClick={() => + openAgentEditCard(agents[index].slug) + } + onClick={() => { + setSelectedAgent(agents[index].slug); + chatInputRef.current?.focus(); + }} > {icon} {agents[index].name} @@ -299,6 +371,7 @@ function ChatBodyData(props: ChatBodyDataProps) { conversationId={null} isMobileWidth={props.isMobileWidth} setUploadedFiles={props.setUploadedFiles} + ref={chatInputRef} />