mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-03 05:29:12 +00:00
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:
@@ -4,7 +4,6 @@ div.chatMessageContainer {
|
||||
margin: 12px;
|
||||
border-radius: 16px;
|
||||
padding: 8px 16px 0 16px;
|
||||
box-shadow: 0 4px 10px var(--box-shadow-color)
|
||||
}
|
||||
|
||||
div.chatMessageWrapper {
|
||||
@@ -79,7 +78,6 @@ div.chatButtons {
|
||||
position: relative;
|
||||
bottom: -12px;
|
||||
background-color: hsla(var(--secondary));
|
||||
box-shadow: 0 4px 10px var(--box-shadow-color);
|
||||
}
|
||||
|
||||
div.chatFooter button {
|
||||
|
||||
@@ -14,6 +14,8 @@ import { ThumbsUp, ThumbsDown, Copy, Brain, Cloud, Folder, Book, Aperture, Speak
|
||||
|
||||
import * as DomPurify from 'dompurify';
|
||||
import { InlineLoading } from '../loading/loading';
|
||||
import { convertColorToTextClass } from '@/app/common/colorUtils';
|
||||
import { AgentData } from '@/app/agents/page';
|
||||
|
||||
const md = new markdownIt({
|
||||
html: true,
|
||||
@@ -72,13 +74,6 @@ export interface OnlineContextData {
|
||||
peopleAlsoAsk: PeopleAlsoAsk[];
|
||||
}
|
||||
|
||||
interface AgentData {
|
||||
name: string;
|
||||
avatar: string;
|
||||
slug: string;
|
||||
persona: string;
|
||||
}
|
||||
|
||||
interface Intent {
|
||||
type: string;
|
||||
query: string;
|
||||
@@ -97,6 +92,7 @@ export interface SingleChatMessage {
|
||||
}
|
||||
rawQuery?: string;
|
||||
intent?: Intent;
|
||||
agent?: AgentData;
|
||||
}
|
||||
|
||||
export interface StreamMessage {
|
||||
@@ -109,6 +105,7 @@ export interface StreamMessage {
|
||||
completed: boolean;
|
||||
rawQuery: string;
|
||||
timestamp: string;
|
||||
agent?: AgentData;
|
||||
}
|
||||
|
||||
export interface ChatHistoryData {
|
||||
@@ -147,16 +144,18 @@ interface ChatMessageProps {
|
||||
customClassName?: string;
|
||||
borderLeftColor?: string;
|
||||
isLastMessage?: boolean;
|
||||
agent?: AgentData;
|
||||
}
|
||||
|
||||
interface TrainOfThoughtProps {
|
||||
message: string;
|
||||
primary: boolean;
|
||||
agentColor: string;
|
||||
}
|
||||
|
||||
function chooseIconFromHeader(header: string, iconColor: string) {
|
||||
const compareHeader = header.toLowerCase();
|
||||
const classNames = `inline mt-1 mr-2 ${iconColor}`;
|
||||
const classNames = `inline mt-1 mr-2 ${iconColor} h-4 w-4`;
|
||||
if (compareHeader.includes("understanding")) {
|
||||
return <Brain className={`${classNames}`} />
|
||||
}
|
||||
@@ -192,7 +191,7 @@ export function TrainOfThought(props: TrainOfThoughtProps) {
|
||||
// The train of thought comes in as a markdown-formatted string. It starts with a heading delimited by two asterisks at the start and end and a colon, followed by the message. Example: **header**: status. This function will parse the message and render it as a div.
|
||||
let extractedHeader = props.message.match(/\*\*(.*)\*\*/);
|
||||
let header = extractedHeader ? extractedHeader[1] : "";
|
||||
const iconColor = props.primary ? 'text-orange-400' : 'text-gray-500';
|
||||
const iconColor = props.primary ? convertColorToTextClass(props.agentColor) : 'text-gray-500';
|
||||
const icon = chooseIconFromHeader(header, iconColor);
|
||||
let markdownRendered = DomPurify.sanitize(md.render(props.message));
|
||||
return (
|
||||
@@ -317,7 +316,7 @@ export default function ChatMessage(props: ChatMessageProps) {
|
||||
}
|
||||
|
||||
function constructClasses(chatMessage: SingleChatMessage) {
|
||||
let classes = [styles.chatMessageContainer];
|
||||
let classes = [styles.chatMessageContainer, "shadow-md"];
|
||||
classes.push(styles[chatMessage.by]);
|
||||
|
||||
if (props.customClassName) {
|
||||
@@ -330,12 +329,9 @@ export default function ChatMessage(props: ChatMessageProps) {
|
||||
function chatMessageWrapperClasses(chatMessage: SingleChatMessage) {
|
||||
let classes = [styles.chatMessageWrapper];
|
||||
classes.push(styles[chatMessage.by]);
|
||||
|
||||
if (chatMessage.by === "khoj") {
|
||||
const dynamicBorderColor = `border-l-${props.borderLeftColor}`;
|
||||
classes.push(`border-l-4 border-opacity-50 border-l-orange-400 ${dynamicBorderColor}`);
|
||||
classes.push(`border-l-4 border-opacity-50 ${"border-l-" + props.borderLeftColor || "border-l-orange-400"}`);
|
||||
}
|
||||
|
||||
return classes.join(' ');
|
||||
}
|
||||
|
||||
@@ -437,7 +433,7 @@ export default function ChatMessage(props: ChatMessageProps) {
|
||||
<div title={formatDate(props.chatMessage.created)} className={`text-gray-400 relative top-0 left-4`}>
|
||||
{renderTimeStamp(props.chatMessage.created)}
|
||||
</div>
|
||||
<div className={styles.chatButtons}>
|
||||
<div className={`${styles.chatButtons} shadow-sm`}>
|
||||
{
|
||||
(props.chatMessage.by === "khoj") &&
|
||||
(
|
||||
|
||||
Reference in New Issue
Block a user