-
-
Notifications
You must be signed in to change notification settings - Fork 266
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
578 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; | ||
import { motion } from "framer-motion"; | ||
import { NoResult, SearchResult, SkeletonSearchResult } from "./SearchResult"; | ||
import { ISearchResult } from "./types"; | ||
|
||
type Props = { | ||
onSubmit: (query: string) => void; | ||
searchQuery: string; | ||
setSearchQuery: (query: string) => void; | ||
isLoading: boolean; | ||
data: ISearchResult; | ||
}; | ||
|
||
export default function AISearchEngine({ | ||
onSubmit, | ||
searchQuery, | ||
setSearchQuery, | ||
isLoading, | ||
data, | ||
}: Props) { | ||
return ( | ||
<div className="max-w-5xl mt-12 mx-auto p-4 min-h-screen"> | ||
<form | ||
onSubmit={(e) => { | ||
e.preventDefault(); | ||
onSubmit(searchQuery); | ||
}} | ||
className="flex mb-8" | ||
> | ||
<input | ||
type="text" | ||
value={searchQuery} | ||
onChange={(e) => setSearchQuery(e.target.value)} | ||
placeholder="Enter your search query..." | ||
className="flex-grow px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-l-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400 bg-white dark:bg-[#1e1e1e] text-gray-900 dark:text-gray-100" | ||
/> | ||
<button | ||
type="submit" | ||
className="px-6 py-2 bg-indigo-600 dark:bg-white text-white dark:text-indigo-600 rounded-r-lg hover:bg-indigo-700 dark:hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-indigo-400" | ||
> | ||
<MagnifyingGlassIcon className="w-5 h-5" /> | ||
</button> | ||
</form> | ||
|
||
<motion.div className="space-y-6"> | ||
{isLoading && ( | ||
<> | ||
<SkeletonSearchResult /> | ||
<SkeletonSearchResult /> | ||
<SkeletonSearchResult /> | ||
</> | ||
)} | ||
{!isLoading && data.length === 0 && <NoResult />} | ||
{!isLoading && | ||
data.length > 0 && | ||
data.map((result, idx) => ( | ||
<SearchResult | ||
key={idx} | ||
context={result?.result?.pageContent} | ||
source={result?.result?.source} | ||
icon={<MagnifyingGlassIcon className="size-4" />} | ||
score={+result?.score} | ||
/> | ||
))} | ||
</motion.div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; | ||
|
||
interface SearchBoxProps { | ||
onSubmit: (query: string) => void; | ||
placeholder?: string; | ||
searchQuery: string; | ||
setSearchQuery: (query: string) => void; | ||
} | ||
|
||
export default function DefaultSearchBox({ | ||
onSubmit, | ||
placeholder = "Find that TPS report, Bob's extension, or the elusive stapler...", | ||
searchQuery, | ||
setSearchQuery, | ||
}: SearchBoxProps) { | ||
const handleSearch = (e: React.FormEvent) => { | ||
e.preventDefault(); | ||
onSubmit(searchQuery); | ||
}; | ||
|
||
return ( | ||
<div className="h-[70vh] flex items-center justify-center"> | ||
<div className="w-full max-w-3xl px-4"> | ||
<form onSubmit={handleSearch} className="relative"> | ||
<textarea | ||
placeholder={placeholder} | ||
value={searchQuery} | ||
onChange={(e) => setSearchQuery(e.target.value)} | ||
className="w-full py-3 pr-16 text-gray-900 border rounded-md outline-none dark:bg-[#1e1e1e] dark:border-gray-700 dark:text-gray-100 bg-white border-gray-300 transition-colors duration-300 resize-none ring-0" | ||
rows={3} | ||
/> | ||
<button | ||
type="submit" | ||
className="absolute right-2 top-1/2 -translate-y-1/2 size-10 bg-indigo-600 dark:bg-white text-white dark:text-indigo-600 rounded-full hover:bg-indigo-700 dark:hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:focus:ring-white focus:ring-opacity-50 transition-all duration-300 transform hover:scale-105" | ||
aria-label="Search" | ||
> | ||
<MagnifyingGlassIcon className="size-5 mx-auto" /> | ||
</button>{" "} | ||
</form> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { motion } from "framer-motion"; | ||
import { useState } from "react"; | ||
|
||
export interface SearchResultProps { | ||
context: string; | ||
source: string; | ||
icon: React.ReactNode; | ||
score: number; | ||
} | ||
|
||
export function SearchResult({ | ||
context, | ||
source, | ||
icon, | ||
score, | ||
}: SearchResultProps) { | ||
const [isExpanded, setIsExpanded] = useState(false); | ||
const maxLength = 250; | ||
|
||
const toggleReadMore = () => { | ||
setIsExpanded(!isExpanded); | ||
}; | ||
|
||
const truncatedContext = isExpanded ? context : context.slice(0, maxLength); | ||
|
||
return ( | ||
<motion.div | ||
initial={{ opacity: 0, y: 20 }} | ||
animate={{ opacity: 1, y: 0 }} | ||
transition={{ duration: 0.3 }} | ||
className="border border-gray-200 dark:border-gray-700 rounded-lg p-4 hover:shadow-md transition-shadow bg-white dark:bg-[#1e1e1e]" | ||
> | ||
<p className="text-gray-600 dark:text-gray-300 mb-3"> | ||
{truncatedContext} | ||
{context.length > maxLength && ( | ||
<> | ||
{!isExpanded && "..."} | ||
<button | ||
onClick={toggleReadMore} | ||
className="text-indigo-600 dark:text-indigo-400 ml-2 hover:underline focus:outline-none" | ||
> | ||
{isExpanded ? "Read less" : "Read more"} | ||
</button> | ||
</> | ||
)} | ||
</p> | ||
<div className="flex items-center text-sm text-gray-500 dark:text-gray-400"> | ||
{icon} | ||
<span className="ml-2">{source}</span> | ||
</div> | ||
<div className="mt-3 pt-3 border-t border-gray-200 dark:border-gray-700 flex items-center justify-between bg-gray-50 dark:bg-[#2a2a2a] rounded-b-lg -mx-4 -mb-4 px-4 py-2"> | ||
<span className="text-sm text-gray-600 dark:text-gray-300"> | ||
Similarity: {`${score}%`} | ||
</span> | ||
</div> | ||
</motion.div> | ||
); | ||
} | ||
export function SkeletonSearchResult() { | ||
return ( | ||
<motion.div | ||
initial={{ opacity: 0, y: 20 }} | ||
animate={{ opacity: 1, y: 0 }} | ||
transition={{ duration: 0.3 }} | ||
className="border border-gray-200 dark:border-gray-700 rounded-lg p-4 hover:shadow-md transition-shadow bg-white dark:bg-[#1e1e1e]" | ||
> | ||
<div className="h-4 w-full bg-gray-200 dark:bg-gray-700 rounded mb-2"></div> | ||
<div className="h-4 w-full bg-gray-200 dark:bg-gray-700 rounded mb-2"></div> | ||
<div className="h-4 w-1/2 bg-gray-200 dark:bg-gray-700 rounded mb-3"></div> | ||
<div className="flex items-center"> | ||
<div className="h-5 w-5 bg-gray-200 dark:bg-gray-700 rounded-full mr-2"></div> | ||
<div className="h-4 w-1/4 bg-gray-200 dark:bg-gray-700 rounded"></div> | ||
</div> | ||
</motion.div> | ||
); | ||
} | ||
|
||
export const NoResult = () => ( | ||
<div className="text-center py-8"> | ||
<p className="text-gray-600 dark:text-gray-400 text-lg">No results found</p> | ||
<p className="text-gray-500 dark:text-gray-500 text-sm mt-2"> | ||
Try adjusting your search query | ||
</p> | ||
</div> | ||
); |
Oops, something went wrong.