mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-10 05:39:11 +00:00
Add some better default states for no files found, prompt to search. Add link to search in the file search compnoent in side panel
This commit is contained in:
@@ -203,7 +203,7 @@ function FilesMenu(props: FilesMenuProps) {
|
|||||||
<Command>
|
<Command>
|
||||||
<CommandInput placeholder="Find file" />
|
<CommandInput placeholder="Find file" />
|
||||||
<CommandList>
|
<CommandList>
|
||||||
<CommandEmpty>No results found.</CommandEmpty>
|
<CommandEmpty>No results found. <Link href="/search">Try advanced search</Link>.</CommandEmpty>
|
||||||
<CommandGroup heading="Quick">
|
<CommandGroup heading="Quick">
|
||||||
<CommandItem
|
<CommandItem
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
|
|||||||
@@ -3,14 +3,15 @@
|
|||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
|
|
||||||
import { useAuthenticatedData } from '../common/auth';
|
import { useAuthenticatedData } from '../common/auth';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import SidePanel from '../components/sidePanel/chatHistorySidePanel';
|
import SidePanel from '../components/sidePanel/chatHistorySidePanel';
|
||||||
import NavMenu from '../components/navMenu/navMenu';
|
import NavMenu from '../components/navMenu/navMenu';
|
||||||
import styles from './search.module.css';
|
import styles from './search.module.css';
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { ArrowLeft, ArrowRight, Folder, FolderOpen, GithubLogo, LinkSimple, MagnifyingGlass, NoteBlank, NotionLogo } from '@phosphor-icons/react';
|
import { ArrowLeft, ArrowRight, FileDashed, FileMagnifyingGlass, Folder, FolderOpen, GithubLogo, Lightbulb, LinkSimple, MagnifyingGlass, NoteBlank, NotionLogo } from '@phosphor-icons/react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
interface AdditionalData {
|
interface AdditionalData {
|
||||||
file: string;
|
file: string;
|
||||||
@@ -37,6 +38,25 @@ function getNoteTypeIcon(source: string) {
|
|||||||
return <NoteBlank className='text-muted-foreground' />;
|
return <NoteBlank className='text-muted-foreground' />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const naturalLanguageSearchQueryExamples = [
|
||||||
|
"What does the paper say about climate change?",
|
||||||
|
"Making a cappuccino at home",
|
||||||
|
"Benefits of eating mangoes",
|
||||||
|
"How to plan a wedding on a budget",
|
||||||
|
"Appointment with Dr. Makinde on 12th August",
|
||||||
|
"Class notes lecture 3 on quantum mechanics",
|
||||||
|
"Painting concepts for acrylics",
|
||||||
|
"Abstract from the paper attention is all you need",
|
||||||
|
"Climbing Everest without oxygen",
|
||||||
|
"Solving a rubik's cube in 30 seconds",
|
||||||
|
"Facts about the planet Mars",
|
||||||
|
"How to make a website using React",
|
||||||
|
"Fish at the bottom of the ocean",
|
||||||
|
"Fish farming Kenya 2021",
|
||||||
|
"How to make a cake without an oven",
|
||||||
|
"Installing a solar panel at home",
|
||||||
|
]
|
||||||
|
|
||||||
interface NoteResultProps {
|
interface NoteResultProps {
|
||||||
note: SearchResult;
|
note: SearchResult;
|
||||||
setFocusSearchResult: (note: SearchResult) => void;
|
setFocusSearchResult: (note: SearchResult) => void;
|
||||||
@@ -117,9 +137,12 @@ export default function Search() {
|
|||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
const [isMobileWidth, setIsMobileWidth] = useState(false);
|
const [isMobileWidth, setIsMobileWidth] = useState(false);
|
||||||
const [title, setTitle] = useState('Search');
|
const [title, setTitle] = useState('Search');
|
||||||
const [searchResults, setSearchResults] = useState<SearchResult[]>([]);
|
const [searchResults, setSearchResults] = useState<SearchResult[] | null>(null);
|
||||||
const [searchResultsLoading, setSearchResultsLoading] = useState(false);
|
const [searchResultsLoading, setSearchResultsLoading] = useState(false);
|
||||||
const [focusSearchResult, setFocusSearchResult] = useState<SearchResult | null>(null);
|
const [focusSearchResult, setFocusSearchResult] = useState<SearchResult | null>(null);
|
||||||
|
const [exampleQuery, setExampleQuery] = useState('');
|
||||||
|
const searchTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsMobileWidth(window.innerWidth < 786);
|
setIsMobileWidth(window.innerWidth < 786);
|
||||||
@@ -128,13 +151,15 @@ export default function Search() {
|
|||||||
setIsMobileWidth(window.innerWidth < 786);
|
setIsMobileWidth(window.innerWidth < 786);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setExampleQuery(naturalLanguageSearchQueryExamples[Math.floor(Math.random() * naturalLanguageSearchQueryExamples.length)]);
|
||||||
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTitle(isMobileWidth ? '' : 'Search');
|
setTitle(isMobileWidth ? '' : 'Search');
|
||||||
}, [isMobileWidth]);
|
}, [isMobileWidth]);
|
||||||
|
|
||||||
function search(query: string) {
|
function search() {
|
||||||
if (searchResultsLoading) {
|
if (searchResultsLoading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -158,6 +183,31 @@ export default function Search() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!searchQuery.trim()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setFocusSearchResult(null);
|
||||||
|
|
||||||
|
if (searchTimeoutRef.current) {
|
||||||
|
clearTimeout(searchTimeoutRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchQuery.trim()) {
|
||||||
|
searchTimeoutRef.current = setTimeout(() => {
|
||||||
|
search();
|
||||||
|
}, 750); // 1000 milliseconds = 1 second
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (searchTimeoutRef.current) {
|
||||||
|
clearTimeout(searchTimeoutRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}, [searchQuery]);
|
||||||
|
|
||||||
console.log('searchResults', searchResults);
|
console.log('searchResults', searchResults);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -179,12 +229,13 @@ export default function Search() {
|
|||||||
<div className='flex justify-between items-center border-2 border-muted p-2 gap-4 rounded-lg'>
|
<div className='flex justify-between items-center border-2 border-muted p-2 gap-4 rounded-lg'>
|
||||||
<MagnifyingGlass className='inline m-2' />
|
<MagnifyingGlass className='inline m-2' />
|
||||||
<Input
|
<Input
|
||||||
|
autoFocus
|
||||||
className='border-none'
|
className='border-none'
|
||||||
onChange={(e) => setSearchQuery(e.currentTarget.value)}
|
onChange={(e) => setSearchQuery(e.currentTarget.value)}
|
||||||
onKeyDown={(e) => e.key === 'Enter' && search(searchQuery)}
|
onKeyDown={(e) => e.key === 'Enter' && search()}
|
||||||
type="search"
|
type="search"
|
||||||
placeholder="Search Documents" />
|
placeholder="Search Documents" />
|
||||||
<button className='px-4 rounded' onClick={() => search(searchQuery)}>
|
<button className='px-4 rounded' onClick={() => search()}>
|
||||||
Find
|
Find
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -199,7 +250,7 @@ export default function Search() {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
!focusSearchResult && searchResults.length > 0 &&
|
!focusSearchResult && searchResults && searchResults.length > 0 &&
|
||||||
<div className='mt-4'>
|
<div className='mt-4'>
|
||||||
<ScrollArea className="h-[80vh]">
|
<ScrollArea className="h-[80vh]">
|
||||||
{
|
{
|
||||||
@@ -214,6 +265,45 @@ export default function Search() {
|
|||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
searchResults == null &&
|
||||||
|
<Card className='flex flex-col items-center justify-center border-none shadow-none'>
|
||||||
|
<CardHeader className='flex flex-col items-center justify-center'>
|
||||||
|
<CardDescription className='border-muted-foreground border w-fit rounded-lg mb-2 text-center text-lg p-4'>
|
||||||
|
<FileMagnifyingGlass weight='fill' className='text-muted-foreground h-10 w-10' />
|
||||||
|
</CardDescription>
|
||||||
|
<CardTitle className='text-center'>
|
||||||
|
Search across your documents
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className='text-muted-foreground items-center justify-center text-center flex'>
|
||||||
|
<Lightbulb className='inline mr-2' /> {exampleQuery}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
searchResults && searchResults.length === 0 &&
|
||||||
|
<Card className='flex flex-col items-center justify-center border-none shadow-none'>
|
||||||
|
<CardHeader className='flex flex-col items-center justify-center'>
|
||||||
|
<CardDescription className='border-muted-foreground border w-fit rounded-lg mb-2 text-center text-lg p-4'>
|
||||||
|
<FileDashed weight='fill' className='text-muted-foreground h-10 w-10' />
|
||||||
|
</CardDescription>
|
||||||
|
<CardTitle className='text-center'>
|
||||||
|
No documents found
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className='text-muted-foreground items-center justify-center text-center flex'>
|
||||||
|
To use search, upload your docs to your account.
|
||||||
|
</div>
|
||||||
|
<Link href="https://docs.khoj.dev/data-sources/share_your_data" className='no-underline'>
|
||||||
|
<div className='mt-4 text-center text-secondary-foreground bg-secondary w-fit m-auto p-2 rounded-lg'>
|
||||||
|
Learn More
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user