You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
76 lines
2.3 KiB
76 lines
2.3 KiB
'use client';
|
|
|
|
import Link from 'next/link';
|
|
import { type Post } from 'contentlayer/generated';
|
|
import Balancer from 'react-wrap-balancer';
|
|
|
|
import { useSearchStore } from '@/stores/search-store';
|
|
import { formatDateTime } from '@/lib/datetime';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
type SearchResultsProps = {
|
|
query: string;
|
|
results: Post[];
|
|
};
|
|
|
|
export function SearchResults({ query, results }: SearchResultsProps) {
|
|
const toggleSearch = useSearchStore((state) => state.toggleSearch);
|
|
|
|
return (
|
|
<ul className="flex flex-col overflow-scroll">
|
|
{results.map((post) => {
|
|
const publishedDate = formatDateTime(post.date);
|
|
|
|
return (
|
|
<li
|
|
key={post.slug}
|
|
className={cn(
|
|
'rounded p-2 transition-none sm:px-8',
|
|
'even:bg-slate-400/30 hover:bg-slate-500/50',
|
|
'dark:even:bg-slate-700/60 dark:hover:bg-slate-400/40',
|
|
)}
|
|
>
|
|
<Link
|
|
href={post.url}
|
|
onClick={toggleSearch}
|
|
className="flex h-fit flex-col"
|
|
>
|
|
<span className="font-semibold text-slate-800 dark:text-rose-50 sm:text-xl">
|
|
<Balancer>{highlightSearchQuery(query, post.title)}</Balancer>
|
|
</span>
|
|
<span className="text-sm text-slate-700 dark:text-rose-50 sm:text-base">
|
|
{highlightSearchQuery(query, post.excerpt)}
|
|
</span>
|
|
<span className="text-sm text-slate-600 dark:text-slate-300">
|
|
{publishedDate.asString} · {publishedDate.asRelativeTimeString}
|
|
</span>
|
|
</Link>
|
|
</li>
|
|
);
|
|
})}
|
|
</ul>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Highlights the search query in the text by wrapping it in a span with the
|
|
* font-extrabold class.
|
|
* @param query The search query
|
|
* @param text The text to highlight
|
|
* @returns The text with the query highlighted
|
|
*/
|
|
function highlightSearchQuery(query: string, text: string) {
|
|
const sanitizedQuery = query.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
return text.split(new RegExp(`(${sanitizedQuery})`, 'gi')).map((part, i) => (
|
|
<span
|
|
key={i}
|
|
className={
|
|
part.toLowerCase() === query.toLowerCase()
|
|
? 'font-extrabold'
|
|
: undefined
|
|
}
|
|
>
|
|
{part}
|
|
</span>
|
|
));
|
|
}
|
|
|