mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-06 21:29:12 +00:00
Format next.js web app with prettier
This commit is contained in:
@@ -1,27 +1,26 @@
|
||||
'use client'
|
||||
import './globals.css';
|
||||
import styles from './page.module.css';
|
||||
import 'katex/dist/katex.min.css';
|
||||
"use client";
|
||||
import "./globals.css";
|
||||
import styles from "./page.module.css";
|
||||
import "katex/dist/katex.min.css";
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import useSWR from 'swr';
|
||||
import Image from 'next/image';
|
||||
import { ArrowCounterClockwise, ClockCounterClockwise } from '@phosphor-icons/react';
|
||||
import React, { useEffect, useState } from "react";
|
||||
import useSWR from "swr";
|
||||
import Image from "next/image";
|
||||
import { ArrowCounterClockwise, ClockCounterClockwise } from "@phosphor-icons/react";
|
||||
|
||||
import { Card, CardTitle } from '@/components/ui/card';
|
||||
import SuggestionCard from '@/app/components/suggestions/suggestionCard';
|
||||
import SidePanel from '@/app/components/sidePanel/chatHistorySidePanel';
|
||||
import Loading from '@/app/components/loading/loading';
|
||||
import ChatInputArea, { ChatOptions } from '@/app/components/chatInputArea/chatInputArea';
|
||||
import { Suggestion, suggestionsData } from '@/app/components/suggestions/suggestionsData';
|
||||
import LoginPrompt from '@/app/components/loginPrompt/loginPrompt';
|
||||
|
||||
import { 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 { Card, CardTitle } from "@/components/ui/card";
|
||||
import SuggestionCard from "@/app/components/suggestions/suggestionCard";
|
||||
import SidePanel from "@/app/components/sidePanel/chatHistorySidePanel";
|
||||
import Loading from "@/app/components/loading/loading";
|
||||
import ChatInputArea, { ChatOptions } from "@/app/components/chatInputArea/chatInputArea";
|
||||
import { Suggestion, suggestionsData } from "@/app/components/suggestions/suggestionsData";
|
||||
import LoginPrompt from "@/app/components/loginPrompt/loginPrompt";
|
||||
|
||||
import { 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";
|
||||
|
||||
interface ChatBodyDataProps {
|
||||
chatOptionsData: ChatOptions | null;
|
||||
@@ -34,9 +33,9 @@ interface ChatBodyDataProps {
|
||||
}
|
||||
|
||||
function ChatBodyData(props: ChatBodyDataProps) {
|
||||
const [message, setMessage] = useState('');
|
||||
const [message, setMessage] = useState("");
|
||||
const [processingMessage, setProcessingMessage] = useState(false);
|
||||
const [greeting, setGreeting] = useState('');
|
||||
const [greeting, setGreeting] = useState("");
|
||||
const [shuffledOptions, setShuffledOptions] = useState<Suggestion[]>([]);
|
||||
const [selectedAgent, setSelectedAgent] = useState<string | null>("khoj");
|
||||
const [agentIcons, setAgentIcons] = useState<JSX.Element[]>([]);
|
||||
@@ -45,8 +44,14 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
||||
|
||||
const onConversationIdChange = props.onConversationIdChange;
|
||||
|
||||
const agentsFetcher = () => window.fetch('/api/agents').then(res => res.json()).catch(err => console.log(err));
|
||||
const { data: agentsData, error } = useSWR<AgentData[]>('agents', agentsFetcher, { revalidateOnFocus: false });
|
||||
const agentsFetcher = () =>
|
||||
window
|
||||
.fetch("/api/agents")
|
||||
.then((res) => res.json())
|
||||
.catch((err) => console.log(err));
|
||||
const { data: agentsData, error } = useSWR<AgentData[]>("agents", agentsFetcher, {
|
||||
revalidateOnFocus: false,
|
||||
});
|
||||
|
||||
function shuffleAndSetOptions() {
|
||||
const shuffled = [...suggestionsData].sort(() => 0.5 - Math.random());
|
||||
@@ -59,14 +64,19 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
||||
// Get today's day
|
||||
const today = new Date();
|
||||
const day = today.getDay();
|
||||
const timeOfDay = today.getHours() >= 17 || today.getHours() < 4 ? 'evening' : today.getHours() >= 12 ? 'afternoon' : 'morning';
|
||||
const timeOfDay =
|
||||
today.getHours() >= 17 || today.getHours() < 4
|
||||
? "evening"
|
||||
: today.getHours() >= 12
|
||||
? "afternoon"
|
||||
: "morning";
|
||||
const nameSuffix = props.userConfig?.given_name ? `, ${props.userConfig?.given_name}` : "";
|
||||
const greetings = [
|
||||
`What would you like to get done${nameSuffix}?`,
|
||||
`Hey${nameSuffix}! How can I help?`,
|
||||
`Good ${timeOfDay}${nameSuffix}! What's on your mind?`,
|
||||
`Ready to breeze through your ${['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][day]}?`,
|
||||
`Want help navigating your ${['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][day]} workload?`
|
||||
`Ready to breeze through your ${["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][day]}?`,
|
||||
`Want help navigating your ${["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][day]} workload?`,
|
||||
];
|
||||
const greeting = greetings[Math.floor(Math.random() * greetings.length)];
|
||||
setGreeting(greeting);
|
||||
@@ -83,8 +93,8 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
||||
const shuffledAgents = agentsData ? [...agentsData].sort(() => 0.5 - Math.random()) : [];
|
||||
const agents = agentsData ? [agentsData[0]] : []; // Always add the first/default agent.
|
||||
|
||||
shuffledAgents.slice(0, nSlice - 1).forEach(agent => {
|
||||
if (!agents.find(a => a.slug === agent.slug)) {
|
||||
shuffledAgents.slice(0, nSlice - 1).forEach((agent) => {
|
||||
if (!agents.find((a) => a.slug === agent.slug)) {
|
||||
agents.push(agent);
|
||||
}
|
||||
});
|
||||
@@ -93,7 +103,16 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
||||
|
||||
//generate colored icons for the selected agents
|
||||
const agentIcons = agents.map(
|
||||
agent => getIconFromIconName(agent.icon, agent.color) || <Image key={agent.name} src={agent.avatar} alt={agent.name} width={50} height={50} />
|
||||
(agent) =>
|
||||
getIconFromIconName(agent.icon, agent.color) || (
|
||||
<Image
|
||||
key={agent.name}
|
||||
src={agent.avatar}
|
||||
alt={agent.name}
|
||||
width={50}
|
||||
height={50}
|
||||
/>
|
||||
),
|
||||
);
|
||||
setAgentIcons(agentIcons);
|
||||
}, [agentsData, props.isMobileWidth]);
|
||||
@@ -110,19 +129,18 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
||||
const newConversationId = await createNewConversation(selectedAgent || "khoj");
|
||||
onConversationIdChange?.(newConversationId);
|
||||
window.location.href = `/chat?conversationId=${newConversationId}`;
|
||||
localStorage.setItem('message', message);
|
||||
}
|
||||
catch (error) {
|
||||
localStorage.setItem("message", message);
|
||||
} catch (error) {
|
||||
console.error("Error creating new conversation:", error);
|
||||
setProcessingMessage(false);
|
||||
}
|
||||
setMessage('');
|
||||
setMessage("");
|
||||
}
|
||||
};
|
||||
processMessage();
|
||||
if (message) {
|
||||
setProcessingMessage(true);
|
||||
};
|
||||
}
|
||||
}, [selectedAgent, message, processingMessage, onConversationIdChange]);
|
||||
|
||||
function fillArea(link: string, type: string, prompt: string) {
|
||||
@@ -150,44 +168,54 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
||||
|
||||
return (
|
||||
<div className={`${styles.homeGreetings} w-full md:w-auto`}>
|
||||
{
|
||||
showLoginPrompt && (
|
||||
<LoginPrompt
|
||||
onOpenChange={setShowLoginPrompt}
|
||||
loginRedirectMessage={"Login to your second brain"} />
|
||||
)
|
||||
}
|
||||
{showLoginPrompt && (
|
||||
<LoginPrompt
|
||||
onOpenChange={setShowLoginPrompt}
|
||||
loginRedirectMessage={"Login to your second brain"}
|
||||
/>
|
||||
)}
|
||||
<div className={`w-full text-center justify-end content-end`}>
|
||||
<div className="items-center">
|
||||
<h1 className="text-2xl md:text-3xl text-center w-fit pb-6 px-4 mx-auto">{greeting}</h1>
|
||||
<h1 className="text-2xl md:text-3xl text-center w-fit pb-6 px-4 mx-auto">
|
||||
{greeting}
|
||||
</h1>
|
||||
</div>
|
||||
{
|
||||
!props.isMobileWidth &&
|
||||
{!props.isMobileWidth && (
|
||||
<div className="flex pb-6 gap-2 items-center justify-center">
|
||||
{agentIcons.map((icon, index) => (
|
||||
<Card
|
||||
key={`${index}-${agents[index].slug}`}
|
||||
className={
|
||||
`${selectedAgent === agents[index].slug ?
|
||||
convertColorToBorderClass(agents[index].color) : 'border-stone-100 dark:border-neutral-700 text-muted-foreground'}
|
||||
hover:cursor-pointer rounded-lg px-2 py-2`}>
|
||||
className={`${
|
||||
selectedAgent === agents[index].slug
|
||||
? convertColorToBorderClass(agents[index].color)
|
||||
: "border-stone-100 dark:border-neutral-700 text-muted-foreground"
|
||||
}
|
||||
hover:cursor-pointer rounded-lg px-2 py-2`}
|
||||
>
|
||||
<CardTitle
|
||||
className='text-center text-md font-medium flex justify-center items-center'
|
||||
onClick={() => setSelectedAgent(agents[index].slug)}>
|
||||
className="text-center text-md font-medium flex justify-center items-center"
|
||||
onClick={() => setSelectedAgent(agents[index].slug)}
|
||||
>
|
||||
{icon} {agents[index].name}
|
||||
</CardTitle>
|
||||
</Card>
|
||||
))}
|
||||
<Card className='border-none shadow-none flex justify-center items-center hover:cursor-pointer' onClick={() => window.location.href = "/agents"}>
|
||||
<CardTitle className="text-center text-md font-normal flex justify-center items-center px-1.5 py-2">See All →</CardTitle>
|
||||
<Card
|
||||
className="border-none shadow-none flex justify-center items-center hover:cursor-pointer"
|
||||
onClick={() => (window.location.href = "/agents")}
|
||||
>
|
||||
<CardTitle className="text-center text-md font-normal flex justify-center items-center px-1.5 py-2">
|
||||
See All →
|
||||
</CardTitle>
|
||||
</Card>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
<div className={`mx-auto ${props.isMobileWidth ? 'w-full' : 'w-fit'}`}>
|
||||
{
|
||||
!props.isMobileWidth &&
|
||||
<div className={`w-full ${styles.inputBox} shadow-lg bg-background align-middle items-center justify-center px-3 py-1 dark:bg-neutral-700 border-stone-100 dark:border-none dark:shadow-none rounded-2xl`}>
|
||||
<div className={`mx-auto ${props.isMobileWidth ? "w-full" : "w-fit"}`}>
|
||||
{!props.isMobileWidth && (
|
||||
<div
|
||||
className={`w-full ${styles.inputBox} shadow-lg bg-background align-middle items-center justify-center px-3 py-1 dark:bg-neutral-700 border-stone-100 dark:border-none dark:shadow-none rounded-2xl`}
|
||||
>
|
||||
<ChatInputArea
|
||||
isLoggedIn={props.isLoggedIn}
|
||||
sendMessage={(message) => setMessage(message)}
|
||||
@@ -195,22 +223,30 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
||||
chatOptionsData={props.chatOptionsData}
|
||||
conversationId={null}
|
||||
isMobileWidth={props.isMobileWidth}
|
||||
setUploadedFiles={props.setUploadedFiles} />
|
||||
setUploadedFiles={props.setUploadedFiles}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
<div className={`${styles.suggestions} w-full ${props.isMobileWidth ? 'grid' : 'flex flex-row'} justify-center items-center`}>
|
||||
)}
|
||||
<div
|
||||
className={`${styles.suggestions} w-full ${props.isMobileWidth ? "grid" : "flex flex-row"} justify-center items-center`}
|
||||
>
|
||||
{shuffledOptions.map((suggestion, index) => (
|
||||
<div
|
||||
key={`${suggestion.type} ${suggestion.description}`}
|
||||
onClick={(event) => {
|
||||
if (props.isLoggedIn) {
|
||||
fillArea(suggestion.link, suggestion.type, suggestion.description);
|
||||
fillArea(
|
||||
suggestion.link,
|
||||
suggestion.type,
|
||||
suggestion.description,
|
||||
);
|
||||
} else {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setShowLoginPrompt(true);
|
||||
}
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
<SuggestionCard
|
||||
key={suggestion.type + Math.random()}
|
||||
title={suggestion.type}
|
||||
@@ -224,31 +260,40 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
||||
<div className="flex items-center justify-center margin-auto">
|
||||
<button
|
||||
onClick={shuffleSuggestionsCards}
|
||||
className="m-2 p-1.5 rounded-lg dark:hover:bg-[var(--background-color)] hover:bg-stone-100 border border-stone-100 text-sm text-stone-500 dark:text-stone-300 dark:border-neutral-700">
|
||||
More Ideas <ArrowCounterClockwise className='h-4 w-4 inline' />
|
||||
className="m-2 p-1.5 rounded-lg dark:hover:bg-[var(--background-color)] hover:bg-stone-100 border border-stone-100 text-sm text-stone-500 dark:text-stone-300 dark:border-neutral-700"
|
||||
>
|
||||
More Ideas <ArrowCounterClockwise className="h-4 w-4 inline" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
props.isMobileWidth &&
|
||||
{props.isMobileWidth && (
|
||||
<>
|
||||
<div className={`${styles.inputBox} pt-1 shadow-[0_-20px_25px_-5px_rgba(0,0,0,0.1)] dark:bg-neutral-700 bg-background align-middle items-center justify-center pb-3 mx-1 rounded-t-2xl rounded-b-none`}>
|
||||
<div
|
||||
className={`${styles.inputBox} pt-1 shadow-[0_-20px_25px_-5px_rgba(0,0,0,0.1)] dark:bg-neutral-700 bg-background align-middle items-center justify-center pb-3 mx-1 rounded-t-2xl rounded-b-none`}
|
||||
>
|
||||
<div className="flex gap-2 items-center justify-left pt-1 pb-2 px-12">
|
||||
{agentIcons.map((icon, index) => (
|
||||
<Card
|
||||
key={`${index}-${agents[index].slug}`}
|
||||
className={
|
||||
`${selectedAgent === agents[index].slug ? convertColorToBorderClass(agents[index].color) : 'border-muted text-muted-foreground'} hover:cursor-pointer`
|
||||
}>
|
||||
className={`${selectedAgent === agents[index].slug ? convertColorToBorderClass(agents[index].color) : "border-muted text-muted-foreground"} hover:cursor-pointer`}
|
||||
>
|
||||
<CardTitle
|
||||
className='text-center text-xs font-medium flex justify-center items-center px-1.5 py-1'
|
||||
onClick={() => setSelectedAgent(agents[index].slug)}>
|
||||
className="text-center text-xs font-medium flex justify-center items-center px-1.5 py-1"
|
||||
onClick={() => setSelectedAgent(agents[index].slug)}
|
||||
>
|
||||
{icon} {agents[index].name}
|
||||
</CardTitle>
|
||||
</Card>
|
||||
))}
|
||||
<Card className='border-none shadow-none flex justify-center items-center hover:cursor-pointer' onClick={() => window.location.href = "/agents"}>
|
||||
<CardTitle className={`text-center ${props.isMobileWidth ? 'text-xs' : 'text-md'} font-normal flex justify-center items-center px-1.5 py-2`}>See All →</CardTitle>
|
||||
<Card
|
||||
className="border-none shadow-none flex justify-center items-center hover:cursor-pointer"
|
||||
onClick={() => (window.location.href = "/agents")}
|
||||
>
|
||||
<CardTitle
|
||||
className={`text-center ${props.isMobileWidth ? "text-xs" : "text-md"} font-normal flex justify-center items-center px-1.5 py-2`}
|
||||
>
|
||||
See All →
|
||||
</CardTitle>
|
||||
</Card>
|
||||
</div>
|
||||
<ChatInputArea
|
||||
@@ -258,10 +303,11 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
||||
chatOptionsData={props.chatOptionsData}
|
||||
conversationId={null}
|
||||
isMobileWidth={props.isMobileWidth}
|
||||
setUploadedFiles={props.setUploadedFiles} />
|
||||
setUploadedFiles={props.setUploadedFiles}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -273,7 +319,7 @@ export default function Home() {
|
||||
const [uploadedFiles, setUploadedFiles] = useState<string[]>([]);
|
||||
const [isMobileWidth, setIsMobileWidth] = useState(false);
|
||||
|
||||
const {userConfig: initialUserConfig, isLoadingUserConfig} = useUserConfig(true);
|
||||
const { userConfig: initialUserConfig, isLoadingUserConfig } = useUserConfig(true);
|
||||
const [userConfig, setUserConfig] = useState<UserConfig | null>(null);
|
||||
|
||||
const authenticatedData = useAuthenticatedData();
|
||||
@@ -287,25 +333,24 @@ export default function Home() {
|
||||
}, [initialUserConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/api/chat/options')
|
||||
.then(response => response.json())
|
||||
fetch("/api/chat/options")
|
||||
.then((response) => response.json())
|
||||
.then((data: ChatOptions) => {
|
||||
setLoading(false);
|
||||
if (data) {
|
||||
setChatOptionsData(data);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
return;
|
||||
});
|
||||
|
||||
setIsMobileWidth(window.innerWidth < 786);
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
window.addEventListener("resize", () => {
|
||||
setIsMobileWidth(window.innerWidth < 786);
|
||||
});
|
||||
|
||||
}, []);
|
||||
|
||||
if (isLoading) {
|
||||
@@ -314,9 +359,7 @@ export default function Home() {
|
||||
|
||||
return (
|
||||
<div className={`${styles.main} ${styles.chatLayout}`}>
|
||||
<title>
|
||||
Khoj AI - Your Second Brain
|
||||
</title>
|
||||
<title>Khoj AI - Your Second Brain</title>
|
||||
<div className={`${styles.sidePanel}`}>
|
||||
<SidePanel
|
||||
conversationId={conversationId}
|
||||
|
||||
Reference in New Issue
Block a user