Skip to content

Commit

Permalink
Merge pull request #440 from SujalXplores/feat/search-chats
Browse files Browse the repository at this point in the history
Add search chats support
  • Loading branch information
thecodacus authored Nov 29, 2024
2 parents a0ba540 + b471273 commit 02f4de4
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 4 deletions.
29 changes: 25 additions & 4 deletions app/components/sidebar/Menu.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { cubicEasingFn } from '~/utils/easings';
import { logger } from '~/utils/logger';
import { HistoryItem } from './HistoryItem';
import { binDates } from './date-binning';
import { useSearchFilter } from '~/lib/hooks/useSearchFilter';

const menuVariants = {
closed: {
Expand Down Expand Up @@ -39,6 +40,11 @@ export function Menu() {
const [open, setOpen] = useState(false);
const [dialogContent, setDialogContent] = useState<DialogContent>(null);

const { filteredItems: filteredList, handleSearchChange } = useSearchFilter({
items: list,
searchFields: ['description'],
});

const loadEntries = useCallback(() => {
if (db) {
getAll(db)
Expand Down Expand Up @@ -115,11 +121,11 @@ export function Menu() {
initial="closed"
animate={open ? 'open' : 'closed'}
variants={menuVariants}
className="flex flex-col side-menu fixed top-0 w-[350px] h-full bg-bolt-elements-background-depth-2 border-r rounded-r-3xl border-bolt-elements-borderColor z-sidebar shadow-xl shadow-bolt-elements-sidebar-dropdownShadow text-sm"
className="flex selection-accent flex-col side-menu fixed top-0 w-[350px] h-full bg-bolt-elements-background-depth-2 border-r rounded-r-3xl border-bolt-elements-borderColor z-sidebar shadow-xl shadow-bolt-elements-sidebar-dropdownShadow text-sm"
>
<div className="flex items-center h-[var(--header-height)]">{/* Placeholder */}</div>
<div className="flex-1 flex flex-col h-full w-full overflow-hidden">
<div className="p-4">
<div className="p-4 select-none">
<a
href="/"
className="flex gap-2 items-center bg-bolt-elements-sidebar-buttonBackgroundDefault text-bolt-elements-sidebar-buttonText hover:bg-bolt-elements-sidebar-buttonBackgroundHover rounded-md p-2 transition-theme"
Expand All @@ -128,11 +134,26 @@ export function Menu() {
Start new chat
</a>
</div>
<div className="pl-4 pr-4 my-2">
<div className="relative w-full">
<input
className="w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor"
type="search"
placeholder="Search"
onChange={handleSearchChange}
aria-label="Search chats"
/>
</div>
</div>
<div className="text-bolt-elements-textPrimary font-medium pl-6 pr-5 my-2">Your Chats</div>
<div className="flex-1 overflow-auto pl-4 pr-5 pb-5">
{list.length === 0 && <div className="pl-2 text-bolt-elements-textTertiary">No previous conversations</div>}
{filteredList.length === 0 && (
<div className="pl-2 text-bolt-elements-textTertiary">
{list.length === 0 ? 'No previous conversations' : 'No matches found'}
</div>
)}
<DialogRoot open={dialogContent !== null}>
{binDates(list).map(({ category, items }) => (
{binDates(filteredList).map(({ category, items }) => (
<div key={category} className="mt-4 first:mt-0 space-y-1">
<div className="text-bolt-elements-textTertiary sticky top-0 z-1 bg-bolt-elements-background-depth-2 pl-2 pt-2 pb-1">
{category}
Expand Down
52 changes: 52 additions & 0 deletions app/lib/hooks/useSearchFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useState, useMemo, useCallback } from 'react';
import { debounce } from '~/utils/debounce';
import type { ChatHistoryItem } from '~/lib/persistence';

interface UseSearchFilterOptions {
items: ChatHistoryItem[];
searchFields?: (keyof ChatHistoryItem)[];
debounceMs?: number;
}

export function useSearchFilter({
items = [],
searchFields = ['description'],
debounceMs = 300,
}: UseSearchFilterOptions) {
const [searchQuery, setSearchQuery] = useState('');

const debouncedSetSearch = useCallback(debounce(setSearchQuery, debounceMs), []);

const handleSearchChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
debouncedSetSearch(event.target.value);
},
[debouncedSetSearch],
);

const filteredItems = useMemo(() => {
if (!searchQuery.trim()) {
return items;
}

const query = searchQuery.toLowerCase();

return items.filter((item) =>
searchFields.some((field) => {
const value = item[field];

if (typeof value === 'string') {
return value.toLowerCase().includes(query);
}

return false;
}),
);
}, [items, searchQuery, searchFields]);

return {
searchQuery,
filteredItems,
handleSearchChange,
};
}

0 comments on commit 02f4de4

Please sign in to comment.