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.
84 lines
2.5 KiB
84 lines
2.5 KiB
'use client';
|
|
|
|
import { useEffect, useMemo } from 'react';
|
|
import { type Post } from 'contentlayer/generated';
|
|
import { ChevronUp } from 'lucide-react';
|
|
import { shallow } from 'zustand/shallow';
|
|
|
|
import { useSearchStore } from '@/stores/search-store';
|
|
import { SearchInput } from '@/components/search-input';
|
|
import { SearchResults } from '@/components/search-results';
|
|
import { SearchTags } from '@/components/search-tags';
|
|
import { searchPosts } from '@/lib/search';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
type SearchProps = {
|
|
posts: Post[];
|
|
};
|
|
|
|
export function Search({ posts }: SearchProps) {
|
|
const { query, isSearching, toggleSearch } = useSearchStore(
|
|
(state) => ({
|
|
query: state.query,
|
|
isSearching: state.isSearching,
|
|
toggleSearch: state.toggleSearch,
|
|
}),
|
|
shallow,
|
|
);
|
|
|
|
const results = useMemo(() => searchPosts(query, posts), [query, posts]);
|
|
|
|
useEffect(() => {
|
|
// toggle search on cmd+k or ctrl+k
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
|
|
e.preventDefault();
|
|
toggleSearch();
|
|
}
|
|
};
|
|
document.addEventListener('keydown', handleKeyDown);
|
|
|
|
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
}, [toggleSearch]);
|
|
|
|
if (!isSearching) return null;
|
|
|
|
return (
|
|
<section
|
|
className={cn(
|
|
'fixed left-1/2 top-1/2 z-50 h-fit max-h-[80vh] w-5/6 max-w-3xl -translate-x-1/2 -translate-y-1/2',
|
|
'flex flex-col rounded-md border-2 p-4 backdrop-blur-md',
|
|
'border-slate-400 bg-slate-200/40',
|
|
'dark:border-slate-500 dark:bg-slate-600/80',
|
|
)}
|
|
>
|
|
<div className="mb-2 flex h-fit flex-row items-center">
|
|
<SearchInput hasResults={results.length > 0} />
|
|
<button onClick={toggleSearch}>
|
|
<ChevronUp
|
|
className="icon-base ml-2 text-slate-400 dark:text-slate-400"
|
|
aria-label="Close Search"
|
|
/>
|
|
</button>
|
|
</div>
|
|
|
|
<SearchResults query={query} results={results} />
|
|
|
|
{results.length > 0 && (
|
|
<hr className="my-2 border-slate-400 dark:border-slate-500 max-xs:hidden" />
|
|
)}
|
|
|
|
<SearchTags
|
|
posts={posts}
|
|
className={cn(
|
|
'my-2',
|
|
results.length > 0 ? 'max-xs:hidden sm:text-base' : 'sm:text-lg',
|
|
)}
|
|
/>
|
|
|
|
<div className="absolute bottom-1 left-2 text-xs text-slate-600 dark:text-slate-200 max-sm:hidden">
|
|
Toggle with ⌘+K or Ctrl+K
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|
|
|