mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-03 13:19:16 +00:00
Make most major changes for an updated chat UI (#843)
- Updated references panel - Use subtle coloring for chat cards - Chat streaming with train of thought - Side panel with limited sessions, expandable - Manage conversation file filters easily from the side panel - Updated nav menu, easily go to agents/automations/profile - Upload data from the chat UI (on click attachment icon) - Slash command pop-up menu, scrollable and selectable - Dark mode-enabled - Mostly mobile friendly
This commit is contained in:
@@ -11,26 +11,19 @@ menu.menu a {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
menu.menu a.selected {
|
||||
background-color: var(--primary-hover);
|
||||
}
|
||||
|
||||
menu.menu a:hover {
|
||||
background-color: var(--primary-hover);
|
||||
}
|
||||
|
||||
menu.menu {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
a.selected {
|
||||
background-color: hsl(var(--accent));
|
||||
}
|
||||
|
||||
div.titleBar {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
padding: 16px 0;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
padding-left: 12px;
|
||||
padding-right: 32px;
|
||||
padding-top: 16px;
|
||||
padding-bottom: 16px;
|
||||
justify-content: space-between;
|
||||
align-content: space-evenly;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
div.titleBar menu {
|
||||
@@ -75,14 +68,6 @@ div.settingsMenuOptions {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
div.settingsMenuOptions a {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
div.settingsMenuUsername {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
menu.menu span {
|
||||
display: none;
|
||||
@@ -91,4 +76,8 @@ div.settingsMenuUsername {
|
||||
div.settingsMenuOptions {
|
||||
right: 4px;
|
||||
}
|
||||
|
||||
div.titleBar {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,106 +1,164 @@
|
||||
'use client'
|
||||
|
||||
import styles from './navMenu.module.css';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { useAuthenticatedData, UserProfile } from '@/app/common/auth';
|
||||
import { useState } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
Menubar,
|
||||
MenubarContent,
|
||||
MenubarItem,
|
||||
MenubarMenu,
|
||||
MenubarSeparator,
|
||||
MenubarTrigger,
|
||||
} from "@/components/ui/menubar";
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Toggle } from '@/components/ui/toggle';
|
||||
import { Moon } from '@phosphor-icons/react';
|
||||
|
||||
|
||||
interface NavMenuProps {
|
||||
selected: string;
|
||||
showLogo?: boolean;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
function SettingsMenu(props: UserProfile) {
|
||||
const [showSettings, setShowSettings] = useState(false);
|
||||
|
||||
return (
|
||||
<div className={styles.settingsMenu}>
|
||||
<div className={styles.settingsMenuProfile} onClick={() => setShowSettings(!showSettings)}>
|
||||
<Image
|
||||
src={props.photo || "/agents.svg"}
|
||||
alt={props.username}
|
||||
width={50}
|
||||
height={50}
|
||||
/>
|
||||
</div>
|
||||
{showSettings && (
|
||||
<div className={styles.settingsMenuOptions}>
|
||||
<div className={styles.settingsMenuUsername}>{props.username}</div>
|
||||
<Link href="/config">
|
||||
Settings
|
||||
</Link>
|
||||
<Link href="https://github.com/khoj-ai/khoj">
|
||||
Github
|
||||
</Link>
|
||||
<Link href="https://docs.khoj.dev">
|
||||
Help
|
||||
</Link>
|
||||
<Link href="/auth/logout">
|
||||
Logout
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default function NavMenu(props: NavMenuProps) {
|
||||
|
||||
let userData = useAuthenticatedData();
|
||||
const userData = useAuthenticatedData();
|
||||
const [displayTitle, setDisplayTitle] = useState<string>(props.title || props.selected.toUpperCase());
|
||||
|
||||
const [isMobileWidth, setIsMobileWidth] = useState(false);
|
||||
const [darkMode, setDarkMode] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsMobileWidth(window.innerWidth < 768);
|
||||
setDisplayTitle(props.title || props.selected.toUpperCase());
|
||||
|
||||
}, [props.title]);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', () => {
|
||||
setIsMobileWidth(window.innerWidth < 768);
|
||||
});
|
||||
|
||||
if (localStorage.getItem('theme') === 'dark') {
|
||||
document.documentElement.classList.add('dark');
|
||||
setDarkMode(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
toggleDarkMode(darkMode);
|
||||
}, [darkMode]);
|
||||
|
||||
function toggleDarkMode(darkMode: boolean) {
|
||||
if (darkMode) {
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
localStorage.setItem('theme', darkMode ? 'dark' : 'light');
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.titleBar}>
|
||||
<Link href="/">
|
||||
<Image
|
||||
src="/khoj-logo.svg"
|
||||
alt="Khoj Logo"
|
||||
className={styles.logo}
|
||||
width={100}
|
||||
height={50}
|
||||
priority
|
||||
/>
|
||||
</Link>
|
||||
<menu className={styles.menu}>
|
||||
<a className={props.selected === "Chat" ? styles.selected : ""} href = '/chat'>
|
||||
<Image
|
||||
src="/chat.svg"
|
||||
alt="Chat Logo"
|
||||
className={styles.lgoo}
|
||||
width={24}
|
||||
height={24}
|
||||
priority
|
||||
/>
|
||||
<span>
|
||||
Chat
|
||||
</span>
|
||||
</a>
|
||||
<a className={props.selected === "Agents" ? styles.selected : ""} href='/agents'>
|
||||
<Image
|
||||
src="/agents.svg"
|
||||
alt="Agent Logo"
|
||||
className={styles.lgoo}
|
||||
width={24}
|
||||
height={24}
|
||||
priority
|
||||
/>
|
||||
<span>
|
||||
Agents
|
||||
</span>
|
||||
</a>
|
||||
<a className={props.selected === "Automations" ? styles.selected : ""} href = '/automations'>
|
||||
<Image
|
||||
src="/automation.svg"
|
||||
alt="Automation Logo"
|
||||
className={styles.lgoo}
|
||||
width={24}
|
||||
height={24}
|
||||
priority
|
||||
/>
|
||||
<span>
|
||||
Automations
|
||||
</span>
|
||||
</a>
|
||||
{userData && <SettingsMenu {...userData} />}
|
||||
</menu>
|
||||
<div className={`text-nowrap text-ellipsis overflow-hidden max-w-screen-md grid items-top font-bold mr-8`}>
|
||||
{displayTitle && <h2 className={`text-lg text-ellipsis whitespace-nowrap overflow-x-hidden`} >{displayTitle}</h2>}
|
||||
</div>
|
||||
{
|
||||
isMobileWidth ?
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>=</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem>
|
||||
<Link href='/chat' className={`${props.selected.toLowerCase() === 'chat' ? styles.selected : ''} hover:bg-background`}>Chat</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<Link href='/agents' className={`${props.selected.toLowerCase() === 'agent' ? styles.selected : ''} hover:bg-background`}>Agents</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<Link href='/automations' className={`${props.selected.toLowerCase() === 'automations' ? styles.selected : ''} hover:bg-background`}>Automations</Link>
|
||||
</DropdownMenuItem>
|
||||
{userData && <>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuLabel>Profile</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<Link href="/config">Settings</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<Link href="https://docs.khoj.dev">Help</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<Link href="/auth/logout">Logout</Link>
|
||||
</DropdownMenuItem>
|
||||
</>}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
:
|
||||
<Menubar className='items-top inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground'>
|
||||
<MenubarMenu>
|
||||
<Link href='/chat' target="_blank" rel="noreferrer" className={`${props.selected.toLowerCase() === 'chat' ? styles.selected : ''} hover:bg-background`}>
|
||||
<MenubarTrigger>Chat</MenubarTrigger>
|
||||
</Link>
|
||||
</MenubarMenu>
|
||||
<MenubarMenu>
|
||||
<Link href='/agents' target="_blank" rel="noreferrer" className={`${props.selected.toLowerCase() === 'agent' ? styles.selected : ''} hover:bg-background`}>
|
||||
<MenubarTrigger>Agents</MenubarTrigger>
|
||||
</Link>
|
||||
</MenubarMenu>
|
||||
<MenubarMenu>
|
||||
<Link href='/automations' target="_blank" rel="noreferrer" className={`${props.selected.toLowerCase() === 'automations' ? styles.selected : ''} hover:bg-background`}>
|
||||
<MenubarTrigger>Automations</MenubarTrigger>
|
||||
</Link>
|
||||
</MenubarMenu>
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger>Profile</MenubarTrigger>
|
||||
<MenubarContent>
|
||||
<MenubarItem>
|
||||
<Toggle
|
||||
pressed={darkMode}
|
||||
onClick={() => {
|
||||
setDarkMode(!darkMode)
|
||||
}
|
||||
}>
|
||||
<Moon />
|
||||
</Toggle>
|
||||
</MenubarItem>
|
||||
{userData &&
|
||||
<>
|
||||
<MenubarItem>
|
||||
<Link href="/config">
|
||||
Settings
|
||||
</Link>
|
||||
</MenubarItem>
|
||||
<MenubarSeparator />
|
||||
<MenubarItem>
|
||||
<Link href="https://docs.khoj.dev">
|
||||
Help
|
||||
</Link>
|
||||
</MenubarItem>
|
||||
<MenubarSeparator />
|
||||
<MenubarItem>
|
||||
<Link href="/auth/logout">
|
||||
Logout
|
||||
</Link>
|
||||
</MenubarItem>
|
||||
</>
|
||||
}
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
</Menubar>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user